mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
Merge m-c to b2g-i
This commit is contained in:
commit
4457b52a0c
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1212764 - Clobber needed for bug 957911
|
||||
Bug 1212347 - Disable geckoview_example by default and forget build artifacts.
|
||||
|
@ -123,12 +123,12 @@ onDisable.define(Theme, (theme, {window, newTheme}) => {
|
||||
|
||||
const LightTheme = Theme({
|
||||
name: "theme-light",
|
||||
styles: "chrome://browser/skin/devtools/light-theme.css",
|
||||
styles: "chrome://devtools/skin/themes/light-theme.css",
|
||||
});
|
||||
|
||||
const DarkTheme = Theme({
|
||||
name: "theme-dark",
|
||||
styles: "chrome://browser/skin/devtools/dark-theme.css",
|
||||
styles: "chrome://devtools/skin/themes/dark-theme.css",
|
||||
});
|
||||
|
||||
exports.LightTheme = LightTheme;
|
||||
|
@ -48,11 +48,17 @@ html[dir="rtl"] .conversation-toolbar > li {
|
||||
|
||||
.conversation-toolbar .btn {
|
||||
background-position: center;
|
||||
background-size: 24px;
|
||||
background-size: 28px;
|
||||
background-repeat: no-repeat;
|
||||
background-color: transparent;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
height: 28px;
|
||||
width: 33px;
|
||||
}
|
||||
|
||||
.btn-hangup-entry > .btn {
|
||||
/* Make the button the width of the background, so that we don't get an
|
||||
extra gap which appears to push the toolbar in further than necessary */
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.conversation-toolbar-media-btn-group-box {
|
||||
|
@ -26,7 +26,7 @@ npm_install:
|
||||
.PHONY: dist
|
||||
dist:
|
||||
mkdir -p dist
|
||||
cp -pR content dist
|
||||
cp -pR content/* dist
|
||||
NODE_ENV="production" $(NODE_LOCAL_BIN)/webpack \
|
||||
-p -v --display-errors
|
||||
sed 's#webappEntryPoint.js#js/standalone.js#' \
|
||||
|
@ -52,11 +52,18 @@ function chromeTimeToDate(aTime)
|
||||
* GUID of the folder where items will be inserted
|
||||
* @param items
|
||||
* bookmark items to be inserted
|
||||
* @param errorAccumulator
|
||||
* function that gets called with any errors thrown so we don't drop them on the floor.
|
||||
*/
|
||||
function* insertBookmarkItems(parentGuid, items) {
|
||||
function* insertBookmarkItems(parentGuid, items, errorAccumulator) {
|
||||
for (let item of items) {
|
||||
try {
|
||||
if (item.type == "url") {
|
||||
if (item.url.trim().startsWith("chrome:")) {
|
||||
// Skip invalid chrome URIs. Creating an actual URI always reports
|
||||
// messages to the console, so we avoid doing that.
|
||||
continue;
|
||||
}
|
||||
yield PlacesUtils.bookmarks.insert({
|
||||
parentGuid, url: item.url, title: item.name
|
||||
});
|
||||
@ -65,10 +72,11 @@ function* insertBookmarkItems(parentGuid, items) {
|
||||
parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: item.name
|
||||
})).guid;
|
||||
|
||||
yield insertBookmarkItems(newFolderGuid, item.children);
|
||||
yield insertBookmarkItems(newFolderGuid, item.children, errorAccumulator);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
errorAccumulator(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,6 +210,8 @@ function GetBookmarksResource(aProfileFolder) {
|
||||
|
||||
migrate: function(aCallback) {
|
||||
return Task.spawn(function* () {
|
||||
let gotErrors = false;
|
||||
let errorGatherer = () => gotErrors = true;
|
||||
let jsonStream = yield new Promise(resolve =>
|
||||
NetUtil.asyncFetch({ uri: NetUtil.newURI(bookmarksFile),
|
||||
loadUsingSystemPrincipal: true
|
||||
@ -230,7 +240,7 @@ function GetBookmarksResource(aProfileFolder) {
|
||||
parentGuid =
|
||||
yield MigrationUtils.createImportedBookmarksFolder("Chrome", parentGuid);
|
||||
}
|
||||
yield insertBookmarkItems(parentGuid, roots.bookmark_bar.children);
|
||||
yield insertBookmarkItems(parentGuid, roots.bookmark_bar.children, errorGatherer);
|
||||
}
|
||||
|
||||
// Importing bookmark menu items
|
||||
@ -242,10 +252,13 @@ function GetBookmarksResource(aProfileFolder) {
|
||||
parentGuid =
|
||||
yield MigrationUtils.createImportedBookmarksFolder("Chrome", parentGuid);
|
||||
}
|
||||
yield insertBookmarkItems(parentGuid, roots.other.children);
|
||||
yield insertBookmarkItems(parentGuid, roots.other.children, errorGatherer);
|
||||
}
|
||||
if (gotErrors) {
|
||||
throw "The migration included errors.";
|
||||
}
|
||||
}.bind(this)).then(() => aCallback(true),
|
||||
e => { Cu.reportError(e); aCallback(false) });
|
||||
e => aCallback(false));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -657,19 +657,35 @@ Cookies.prototype = {
|
||||
* - Creation time least significant integer
|
||||
* - Record delimiter "*"
|
||||
*
|
||||
* Unfortunately, "*" can also occur inside the value of the cookie, so we
|
||||
* can't rely exclusively on it as a record separator.
|
||||
*
|
||||
* @note All the times are in FILETIME format.
|
||||
*/
|
||||
_parseCookieBuffer(aTextBuffer) {
|
||||
// Note the last record is an empty string.
|
||||
let records = [r for each (r in aTextBuffer.split("*\n")) if (r)];
|
||||
// Note the last record is an empty string...
|
||||
let records = [];
|
||||
let lines = aTextBuffer.split("\n");
|
||||
while (lines.length > 0) {
|
||||
let record = lines.splice(0, 9);
|
||||
// ... which means this is going to be a 1-element array for that record
|
||||
if (record.length > 1) {
|
||||
records.push(record);
|
||||
}
|
||||
}
|
||||
for (let record of records) {
|
||||
let [name, value, hostpath, flags,
|
||||
expireTimeLo, expireTimeHi] = record.split("\n");
|
||||
expireTimeLo, expireTimeHi] = record;
|
||||
|
||||
// IE stores deleted cookies with a zero-length value, skip them.
|
||||
if (value.length == 0)
|
||||
continue;
|
||||
|
||||
// IE sometimes has cookies created by apps that use "~~local~~/local/file/path"
|
||||
// as the hostpath, ignore those:
|
||||
if (hostpath.startsWith("~~local~~"))
|
||||
continue;
|
||||
|
||||
let hostLen = hostpath.indexOf("/");
|
||||
let host = hostpath.substr(0, hostLen);
|
||||
let path = hostpath.substr(hostLen);
|
||||
|
@ -274,7 +274,7 @@ PlacesController.prototype = {
|
||||
this.newItem("bookmark");
|
||||
break;
|
||||
case "placesCmd_new:separator":
|
||||
this.newSeparator().catch(Cu.reportError);
|
||||
this.newSeparator().catch(Components.utils.reportError);
|
||||
break;
|
||||
case "placesCmd_show:info":
|
||||
this.showBookmarkPropertiesForSelection();
|
||||
@ -1309,8 +1309,8 @@ PlacesController.prototype = {
|
||||
// source, otherwise report an error and fallback to a copy.
|
||||
if (!doCopy &&
|
||||
!PlacesControllerDragHelper.canMoveUnwrappedNode(item)) {
|
||||
Cu.reportError("Tried to move an unmovable Places node, " +
|
||||
"reverting to a copy operation.");
|
||||
Components.utils.reportError("Tried to move an unmovable " +
|
||||
"Places node, reverting to a copy operation.");
|
||||
doCopy = true;
|
||||
}
|
||||
let guid = yield PlacesUIUtils.getTransactionForData(
|
||||
@ -1346,8 +1346,8 @@ PlacesController.prototype = {
|
||||
// If this is not a copy, check for safety that we can move the source,
|
||||
// otherwise report an error and fallback to a copy.
|
||||
if (action != "copy" && !PlacesControllerDragHelper.canMoveUnwrappedNode(items[i])) {
|
||||
Components.utils.reportError("Tried to move an unmovable Places node, " +
|
||||
"reverting to a copy operation.");
|
||||
Components.utils.reportError("Tried to move an unmovable Places " +
|
||||
"node, reverting to a copy operation.");
|
||||
action = "copy";
|
||||
}
|
||||
transactions.push(
|
||||
@ -1625,8 +1625,8 @@ var PlacesControllerDragHelper = {
|
||||
// If this is not a copy, check for safety that we can move the source,
|
||||
// otherwise report an error and fallback to a copy.
|
||||
if (!doCopy && !PlacesControllerDragHelper.canMoveUnwrappedNode(unwrapped)) {
|
||||
Components.utils.reportError("Tried to move an unmovable Places node, " +
|
||||
"reverting to a copy operation.");
|
||||
Components.utils.reportError("Tried to move an unmovable Places " +
|
||||
"node, reverting to a copy operation.");
|
||||
doCopy = true;
|
||||
}
|
||||
if (PlacesUIUtils.useAsyncTransactions) {
|
||||
|
@ -2490,7 +2490,7 @@ var SessionStoreInternal = {
|
||||
global: this._globalState.getState()
|
||||
};
|
||||
|
||||
if (Cu.isModuleLoaded("resource:///modules/devtools/scratchpad-manager.jsm")) {
|
||||
if (Cu.isModuleLoaded("resource:///modules/devtools/client/scratchpad/scratchpad-manager.jsm")) {
|
||||
// get open Scratchpad window states too
|
||||
let scratchpads = ScratchpadManager.getSessionState();
|
||||
if (scratchpads && scratchpads.length) {
|
||||
|
19
browser/config/mozconfigs/macosx64/opt-static-analysis
Normal file
19
browser/config/mozconfigs/macosx64/opt-static-analysis
Normal file
@ -0,0 +1,19 @@
|
||||
MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-optimize
|
||||
ac_add_options --enable-dmd
|
||||
|
||||
# Treat warnings as errors (modulo ALLOW_COMPILER_WARNINGS).
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
||||
ac_add_options --enable-clang-plugin
|
||||
|
||||
. "$topsrcdir/build/macosx/mozconfig.rust"
|
||||
. "$topsrcdir/build/mozconfig.common.override"
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
@ -6,7 +6,7 @@
|
||||
"size": 93197192,
|
||||
"digest": "6ebd8994ac76cf6694c3d9054104219836f47578223c799cb9ba9669cfdee00112e9de56aea9d1e6d9d50ee94a201970555de19794b5fbb7546f58fdf8e59a99",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2",
|
||||
"filename": "clang.tar.xz",
|
||||
"unpack": true,
|
||||
}
|
||||
]
|
||||
|
@ -6,7 +6,7 @@
|
||||
"size": 97314461,
|
||||
"digest": "9a74670fa917f760a4767923485d5166bbd258a8023c8aeb899b8c4d22f2847be76508ac5f26d7d2193318a2bb368a71bc62888d1bfe9d81eb45329a60451aa4",
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.xz",
|
||||
"filename": "clang.tar.bz2",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
|
@ -66,15 +66,37 @@ public class CodeGenerator {
|
||||
return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the C++ type name for this class or any class within the chain
|
||||
* of declaring classes, if the target class matches the given type.
|
||||
*
|
||||
* Return null if the given type does not match any class searched.
|
||||
*/
|
||||
private String getMatchingClassType(final Class<?> type) {
|
||||
Class<?> cls = this.cls;
|
||||
String clsName = this.clsName;
|
||||
|
||||
while (cls != null) {
|
||||
if (type == cls) {
|
||||
return clsName;
|
||||
}
|
||||
cls = cls.getDeclaringClass();
|
||||
clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::")));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
|
||||
if (type == cls) {
|
||||
final String clsName = getMatchingClassType(type);
|
||||
if (clsName != null) {
|
||||
return Utils.getUnqualifiedName(clsName) + "::Param";
|
||||
}
|
||||
return Utils.getNativeParameterType(type, info);
|
||||
}
|
||||
|
||||
private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
|
||||
if (type == cls) {
|
||||
final String clsName = getMatchingClassType(type);
|
||||
if (clsName != null) {
|
||||
return Utils.getUnqualifiedName(clsName) + "::LocalRef";
|
||||
}
|
||||
return Utils.getNativeReturnType(type, info);
|
||||
@ -370,6 +392,7 @@ public class CodeGenerator {
|
||||
if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) {
|
||||
Object val = null;
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
val = field.get(null);
|
||||
} catch (final IllegalAccessException e) {
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
#ifdef MOZ_ANDROID_MAX_SDK_VERSION
|
||||
android:maxSdkVersion="@MOZ_ANDROID_MAX_SDK_VERSION@"
|
||||
#endif
|
||||
android:targetSdkVersion="@ANDROID_TARGET_SDK@"/>
|
||||
android:targetSdkVersion="22"/>
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
|
@ -64,7 +64,7 @@ def updated_env(env):
|
||||
def build_tar_package(tar, name, base, directory):
|
||||
name = os.path.realpath(name)
|
||||
run_in(base, [tar,
|
||||
"-c -%s -f" % "J" if ".xz" in name else "j",
|
||||
"-c -%s -f" % ("J" if ".xz" in name else "j"),
|
||||
name, directory])
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@ support-files =
|
||||
[browser_inspector_delete-selected-node-03.js]
|
||||
[browser_inspector_destroy-after-navigation.js]
|
||||
[browser_inspector_destroy-before-ready.js]
|
||||
[browser_inspector_expand-collapse.js]
|
||||
[browser_inspector_gcli-inspect-command.js]
|
||||
skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988.
|
||||
[browser_inspector_highlighter-01.js]
|
||||
|
@ -0,0 +1,54 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that context menu items exapnd all and collapse are shown properly.
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,<div id='parent-node'><div id='child-node'></div></div>";
|
||||
|
||||
add_task(function* () {
|
||||
|
||||
// Test is often exceeding time-out threshold, similar to Bug 1137765
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
let nodeMenuCollapseElement = inspector.panelDoc.getElementById("node-menu-collapse");
|
||||
let nodeMenuExpandElement = inspector.panelDoc.getElementById("node-menu-expand");
|
||||
|
||||
info("Selecting the parent node");
|
||||
|
||||
let front = yield getNodeFrontForSelector("#parent-node", inspector);
|
||||
|
||||
yield selectNode(front, inspector);
|
||||
|
||||
info("Simulating context menu click on the selected node container.");
|
||||
contextMenuClick(getContainerForNodeFront(front, inspector).tagLine);
|
||||
|
||||
ok(nodeMenuCollapseElement.hasAttribute("disabled"), "Collapse option is disabled");
|
||||
|
||||
ok(!nodeMenuExpandElement.hasAttribute("disabled"), "ExpandAll option is enabled");
|
||||
|
||||
info("Testing whether expansion works properly");
|
||||
dispatchCommandEvent(nodeMenuExpandElement);
|
||||
info("Waiting for expansion to occur");
|
||||
yield waitForMultipleChildrenUpdates(inspector);
|
||||
let markUpContainer = getContainerForNodeFront(front, inspector);
|
||||
ok(markUpContainer.expanded, "node has been successfully expanded");
|
||||
|
||||
//reslecting node after expansion
|
||||
yield selectNode(front, inspector);
|
||||
|
||||
info("Testing whether collapse works properly");
|
||||
info("Simulating context menu click on the selected node container.");
|
||||
contextMenuClick(getContainerForNodeFront(front, inspector).tagLine);
|
||||
|
||||
ok(!nodeMenuCollapseElement.hasAttribute("disabled"), "Collapse option is enabled");
|
||||
|
||||
dispatchCommandEvent(nodeMenuCollapseElement);
|
||||
info("Waiting for collapse to occur");
|
||||
yield waitForMultipleChildrenUpdates(inspector);
|
||||
ok(!markUpContainer.expanded, "node has been successfully collapsed");
|
||||
});
|
@ -481,6 +481,35 @@ function dispatchCommandEvent(node) {
|
||||
node.dispatchEvent(commandEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper that simulates a contextmenu event on the given chrome DOM element.
|
||||
*/
|
||||
function contextMenuClick(element) {
|
||||
let evt = element.ownerDocument.createEvent('MouseEvents');
|
||||
let button = 2; // right click
|
||||
|
||||
evt.initMouseEvent('contextmenu', true, true,
|
||||
element.ownerDocument.defaultView, 1, 0, 0, 0, 0, false,
|
||||
false, false, false, button, null);
|
||||
|
||||
element.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper that fetches a front for a node that matches the given selector or
|
||||
* doctype node if the selector is falsy.
|
||||
*/
|
||||
function* getNodeFrontForSelector(selector, inspector) {
|
||||
if (selector) {
|
||||
info("Retrieving front for selector " + selector);
|
||||
return getNodeFront(selector, inspector);
|
||||
} else {
|
||||
info("Retrieving front for doctype node");
|
||||
let {nodes} = yield inspector.walker.children(inspector.walker.rootNode);
|
||||
return nodes[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulate some common operations for highlighter's tests, to have
|
||||
* the tests cleaner, without exposing directly `inspector`, `highlighter`, and
|
||||
@ -534,3 +563,33 @@ const getHighlighterHelperFor = (type) => Task.async(
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// The expand all operation of the markup-view calls itself recursively and
|
||||
// there's not one event we can wait for to know when it's done
|
||||
// so use this helper function to wait until all recursive children updates are done.
|
||||
function* waitForMultipleChildrenUpdates(inspector) {
|
||||
// As long as child updates are queued up while we wait for an update already
|
||||
// wait again
|
||||
if (inspector.markup._queuedChildUpdates &&
|
||||
inspector.markup._queuedChildUpdates.size) {
|
||||
yield waitForChildrenUpdated(inspector);
|
||||
return yield waitForMultipleChildrenUpdates(inspector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the markupview's _waitForChildren function, wait for all queued
|
||||
* children updates to be handled.
|
||||
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
|
||||
* loaded in the toolbox
|
||||
* @return a promise that resolves when all queued children updates have been
|
||||
* handled
|
||||
*/
|
||||
function waitForChildrenUpdated({markup}) {
|
||||
info("Waiting for queued children updates to be handled");
|
||||
let def = promise.defer();
|
||||
markup._waitForChildren().then(() => {
|
||||
executeSoon(def.resolve);
|
||||
});
|
||||
return def.promise;
|
||||
}
|
||||
|
@ -13,9 +13,9 @@
|
||||
<head>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/devtools/widgets.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/widgets.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/memory.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/themes/common.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/themes/widgets.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/themes/memory.css" type="text/css"/>
|
||||
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://devtools/content/shared/theme-switching.js"/>
|
||||
|
@ -8,10 +8,10 @@ Bug 1067491 - Test taking a census over the RDP.
|
||||
<title>Census Tree 01</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link href="chrome://browser/content/devtools/widgets.css" type="text/css" />
|
||||
<link href="chrome://browser/skin/devtools/light-theme.css" type="text/css" />
|
||||
<link href="chrome://browser/skin/devtools/common.css" type="text/css" />
|
||||
<link href="chrome://browser/skin/devtools/widgets.css" type="text/css" />
|
||||
<link href="chrome://browser/skin/devtools/memory.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/light-theme.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/common.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/widgets.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/memory.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<ul id="container" style="width:100%;height:300px;"></ul>
|
||||
|
@ -1145,8 +1145,7 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
||||
// Then set spectrum's color and listen to color changes to preview them
|
||||
if (this.activeSwatch) {
|
||||
this.currentSwatchColor = this.activeSwatch.nextSibling;
|
||||
this._colorUnit =
|
||||
colorUtils.classifyColor(this.currentSwatchColor.textContent);
|
||||
this._originalColor = this.currentSwatchColor.textContent;
|
||||
let color = this.activeSwatch.style.backgroundColor;
|
||||
this.spectrum.then(spectrum => {
|
||||
spectrum.off("changed", this._onSpectrumColorChange);
|
||||
@ -1224,7 +1223,7 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
||||
|
||||
_toDefaultType: function(color) {
|
||||
let colorObj = new colorUtils.CssColor(color);
|
||||
colorObj.colorUnit = this._colorUnit;
|
||||
colorObj.setAuthoredUnitFromColor(this._originalColor);
|
||||
return colorObj.toString();
|
||||
},
|
||||
|
||||
|
@ -72,6 +72,7 @@ support-files =
|
||||
[browser_ruleview_colorpicker-release-outside-frame.js]
|
||||
[browser_ruleview_colorpicker-revert-on-ESC.js]
|
||||
[browser_ruleview_colorpicker-swatch-displayed.js]
|
||||
[browser_ruleview_colorUnit.js]
|
||||
[browser_ruleview_completion-existing-property_01.js]
|
||||
[browser_ruleview_completion-existing-property_02.js]
|
||||
[browser_ruleview_completion-new-property_01.js]
|
||||
|
@ -55,16 +55,17 @@ function* basicTest() {
|
||||
}
|
||||
|
||||
function* overrideTest() {
|
||||
let gradientText = "(45deg, rgba(255,255,255,0.2) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.2) 75%, transparent 75%, transparent);";
|
||||
let gradientText1 = "(orange, blue);";
|
||||
let gradientText2 = "(pink, teal);";
|
||||
|
||||
let view =
|
||||
yield createTestContent("#testid {" +
|
||||
" background-image: -moz-linear-gradient" +
|
||||
gradientText +
|
||||
" background-image: -webkit-linear-gradient" +
|
||||
gradientText +
|
||||
" background-image: linear-gradient" +
|
||||
gradientText +
|
||||
gradientText1 +
|
||||
" background-image: -ms-linear-gradient" +
|
||||
gradientText2 +
|
||||
" background-image: linear-gradient" +
|
||||
gradientText2 +
|
||||
"} ");
|
||||
|
||||
let elementStyle = view._elementStyle;
|
||||
|
@ -0,0 +1,59 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that color selection respects the user pref.
|
||||
|
||||
const TEST_URI = `
|
||||
<style type='text/css'>
|
||||
#testid {
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
<div id='testid' class='testclass'>Styled Node</div>
|
||||
`;
|
||||
|
||||
add_task(function*() {
|
||||
let TESTS = [
|
||||
{name: "hex", result: "#0F0"},
|
||||
{name: "rgb", result: "rgb(0, 255, 0)"}
|
||||
];
|
||||
|
||||
for (let {name, result} of TESTS) {
|
||||
info("starting test for " + name);
|
||||
Services.prefs.setCharPref("devtools.defaultColorUnit", name);
|
||||
|
||||
yield addTab("data:text/html;charset=utf-8," +
|
||||
encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
yield basicTest(view, name, result);
|
||||
}
|
||||
});
|
||||
|
||||
function* basicTest(view, name, result) {
|
||||
let cPicker = view.tooltips.colorPicker;
|
||||
let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan
|
||||
.querySelector(".ruleview-colorswatch");
|
||||
let onShown = cPicker.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShown;
|
||||
|
||||
let testNode = yield getNode("#testid");
|
||||
|
||||
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
|
||||
element: testNode,
|
||||
name: "color",
|
||||
value: "rgb(0, 255, 0)"
|
||||
});
|
||||
|
||||
let spectrum = yield cPicker.spectrum;
|
||||
let onHidden = cPicker.tooltip.once("hidden");
|
||||
EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
|
||||
is(getRuleViewPropertyValue(view, "#testid", "color"), result,
|
||||
"changing the color used the " + name + " unit");
|
||||
}
|
@ -92,6 +92,20 @@ CssColor.prototype = {
|
||||
this._colorUnit = unit;
|
||||
},
|
||||
|
||||
/**
|
||||
* If the current color unit pref is "authored", then set the
|
||||
* default color unit from the given color. Otherwise, leave the
|
||||
* color unit untouched.
|
||||
*
|
||||
* @param {String} color The color to use
|
||||
*/
|
||||
setAuthoredUnitFromColor: function(color) {
|
||||
if (Services.prefs.getCharPref(COLOR_UNIT_PREF) ===
|
||||
CssColor.COLORUNIT.authored) {
|
||||
this._colorUnit = classifyColor(color);
|
||||
}
|
||||
},
|
||||
|
||||
get hasAlpha() {
|
||||
if (!this.valid) {
|
||||
return false;
|
||||
|
@ -25,5 +25,10 @@ function run_test() {
|
||||
for (let test of CLASSIFY_TESTS) {
|
||||
let result = colorUtils.classifyColor(test.input);
|
||||
equal(result, test.output, "test classifyColor(" + test.input + ")");
|
||||
|
||||
let obj = new colorUtils.CssColor("purple");
|
||||
obj.setAuthoredUnitFromColor(test.input);
|
||||
equal(obj.colorUnit, test.output,
|
||||
"test setAuthoredUnitFromColor(" + test.input + ")");
|
||||
}
|
||||
}
|
||||
|
@ -4106,11 +4106,6 @@ this.DOMApplicationRegistry = {
|
||||
},
|
||||
|
||||
doUninstall: Task.async(function*(aData, aMm) {
|
||||
// The yields here could get stuck forever, so we only hold
|
||||
// a weak reference to the message manager while yielding, to avoid
|
||||
// leaking the whole page associationed with the message manager.
|
||||
aMm = Cu.getWeakReference(aMm);
|
||||
|
||||
let response = "Webapps:Uninstall:Return:OK";
|
||||
|
||||
try {
|
||||
@ -4140,9 +4135,7 @@ this.DOMApplicationRegistry = {
|
||||
response = "Webapps:Uninstall:Return:KO";
|
||||
}
|
||||
|
||||
if ((aMm = aMm.get())) {
|
||||
aMm.sendAsyncMessage(response, this.formatMessage(aData));
|
||||
}
|
||||
aMm.sendAsyncMessage(response, this.formatMessage(aData));
|
||||
}),
|
||||
|
||||
uninstall: function(aManifestURL) {
|
||||
|
@ -114,9 +114,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadGroup)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHttpChannel)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder)
|
||||
@ -490,48 +488,6 @@ EventSource::OnStopRequest(nsIRequest *aRequest,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple helper class that just forwards the redirect callback back
|
||||
* to the EventSource.
|
||||
*/
|
||||
class AsyncVerifyRedirectCallbackFwr final : public nsIAsyncVerifyRedirectCallback
|
||||
{
|
||||
public:
|
||||
explicit AsyncVerifyRedirectCallbackFwr(EventSource* aEventsource)
|
||||
: mEventSource(aEventsource)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackFwr)
|
||||
|
||||
// nsIAsyncVerifyRedirectCallback implementation
|
||||
NS_IMETHOD OnRedirectVerifyCallback(nsresult aResult) override
|
||||
{
|
||||
nsresult rv = mEventSource->OnRedirectVerifyCallback(aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
mEventSource->mErrorLoadOnRedirect = true;
|
||||
mEventSource->DispatchFailConnection();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~AsyncVerifyRedirectCallbackFwr() {}
|
||||
nsRefPtr<EventSource> mEventSource;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackFwr, mEventSource)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackFwr)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncVerifyRedirectCallbackFwr)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncVerifyRedirectCallbackFwr)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// EventSource::nsIChannelEventSink
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -564,56 +520,20 @@ EventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// Prepare to receive callback
|
||||
mRedirectFlags = aFlags;
|
||||
mRedirectCallback = aCallback;
|
||||
mNewRedirectChannel = aNewChannel;
|
||||
|
||||
if (mChannelEventSink) {
|
||||
nsRefPtr<AsyncVerifyRedirectCallbackFwr> fwd =
|
||||
new AsyncVerifyRedirectCallbackFwr(this);
|
||||
|
||||
rv = mChannelEventSink->AsyncOnChannelRedirect(aOldChannel,
|
||||
aNewChannel,
|
||||
aFlags, fwd);
|
||||
if (NS_FAILED(rv)) {
|
||||
mRedirectCallback = nullptr;
|
||||
mNewRedirectChannel = nullptr;
|
||||
mErrorLoadOnRedirect = true;
|
||||
DispatchFailConnection();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
OnRedirectVerifyCallback(NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
EventSource::OnRedirectVerifyCallback(nsresult aResult)
|
||||
{
|
||||
MOZ_ASSERT(mRedirectCallback, "mRedirectCallback not set in callback");
|
||||
MOZ_ASSERT(mNewRedirectChannel,
|
||||
"mNewRedirectChannel not set in callback");
|
||||
|
||||
NS_ENSURE_SUCCESS(aResult, aResult);
|
||||
|
||||
// update our channel
|
||||
|
||||
mHttpChannel = do_QueryInterface(mNewRedirectChannel);
|
||||
mHttpChannel = do_QueryInterface(aNewChannel);
|
||||
NS_ENSURE_STATE(mHttpChannel);
|
||||
|
||||
nsresult rv = SetupHttpChannel();
|
||||
rv = SetupHttpChannel();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if ((mRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) {
|
||||
if ((aFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) {
|
||||
rv = NS_GetFinalChannelURI(mHttpChannel, getter_AddRefs(mSrc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mNewRedirectChannel = nullptr;
|
||||
|
||||
mRedirectCallback->OnRedirectVerifyCallback(aResult);
|
||||
mRedirectCallback = nullptr;
|
||||
aCallback->OnRedirectVerifyCallback(NS_OK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -626,27 +546,12 @@ NS_IMETHODIMP
|
||||
EventSource::GetInterface(const nsIID & aIID,
|
||||
void **aResult)
|
||||
{
|
||||
// Make sure to return ourselves for the channel event sink interface,
|
||||
// no matter what. We can forward these to mNotificationCallbacks
|
||||
// if it wants to get notifications for them. But we
|
||||
// need to see these notifications for proper functioning.
|
||||
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
|
||||
mChannelEventSink = do_GetInterface(mNotificationCallbacks);
|
||||
*aResult = static_cast<nsIChannelEventSink*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now give mNotificationCallbacks (if non-null) a chance to return the
|
||||
// desired interface.
|
||||
if (mNotificationCallbacks) {
|
||||
nsresult rv = mNotificationCallbacks->GetInterface(aIID, aResult);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
|
||||
aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
|
||||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
@ -807,12 +712,14 @@ EventSource::InitChannelAndRequestEventSource()
|
||||
rv = SetupHttpChannel();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
|
||||
mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
|
||||
if (notificationCallbacks != this) {
|
||||
mNotificationCallbacks = notificationCallbacks;
|
||||
mHttpChannel->SetNotificationCallbacks(this);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
|
||||
mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
|
||||
MOZ_ASSERT(!notificationCallbacks);
|
||||
}
|
||||
#endif
|
||||
mHttpChannel->SetNotificationCallbacks(this);
|
||||
|
||||
// Start reading from the channel
|
||||
rv = mHttpChannel->AsyncOpen2(this);
|
||||
@ -878,11 +785,7 @@ EventSource::ResetConnection()
|
||||
mLastConvertionResult = NS_OK;
|
||||
|
||||
mHttpChannel = nullptr;
|
||||
mNotificationCallbacks = nullptr;
|
||||
mChannelEventSink = nullptr;
|
||||
mStatus = PARSE_STATE_OFF;
|
||||
mRedirectCallback = nullptr;
|
||||
mNewRedirectChannel = nullptr;
|
||||
|
||||
mReadyState = CONNECTING;
|
||||
|
||||
|
@ -34,7 +34,6 @@ class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AsyncVerifyRedirectCallbackFwr;
|
||||
struct EventSourceInit;
|
||||
|
||||
class EventSource final : public DOMEventTargetHelper
|
||||
@ -44,8 +43,6 @@ class EventSource final : public DOMEventTargetHelper
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
friend class AsyncVerifyRedirectCallbackFwr;
|
||||
|
||||
public:
|
||||
explicit EventSource(nsPIDOMWindow* aOwnerWindow);
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
@ -232,13 +229,6 @@ protected:
|
||||
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
/**
|
||||
* The notification callbacks the channel had initially.
|
||||
* We want to forward things here as needed.
|
||||
*/
|
||||
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
|
||||
nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> mHttpChannel;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
@ -249,10 +239,6 @@ protected:
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsString mOrigin;
|
||||
|
||||
uint32_t mRedirectFlags;
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
|
||||
nsCOMPtr<nsIChannel> mNewRedirectChannel;
|
||||
|
||||
// Event Source owner information:
|
||||
// - the script file name
|
||||
// - source code line number and column number where the Event Source object
|
||||
|
@ -274,13 +274,27 @@ WindowNamedPropertiesHandler::Create(JSContext* aCx,
|
||||
// Note: since the scope polluter proxy lives on the window's prototype
|
||||
// chain, it needs a singleton type to avoid polluting type information
|
||||
// for properties on the window.
|
||||
JS::Rooted<JSObject*> gsp(aCx);
|
||||
js::ProxyOptions options;
|
||||
options.setSingleton(true);
|
||||
options.setClass(&WindowNamedPropertiesClass.mBase);
|
||||
return js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, aProto,
|
||||
options);
|
||||
|
||||
JS::Rooted<JSObject*> gsp(aCx);
|
||||
gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, aProto,
|
||||
options);
|
||||
if (!gsp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool succeeded;
|
||||
if (!JS_SetImmutablePrototype(aCx, gsp, &succeeded)) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(succeeded,
|
||||
"errors making the [[Prototype]] of the named properties object "
|
||||
"immutable should have been JSAPI failures, not !succeeded");
|
||||
|
||||
return gsp;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -199,6 +199,49 @@ MessageEvent::InitMessageEvent(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MessageEvent::InitMessageEvent(JSContext* aCx, const nsAString& aType,
|
||||
bool aCanBubble, bool aCancelable,
|
||||
JS::Handle<JS::Value> aData,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aLastEventId,
|
||||
const Nullable<WindowProxyOrMessagePort>& aSource,
|
||||
const Nullable<Sequence<OwningNonNull<MessagePort>>>& aPorts,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRv = Event::InitEvent(aType, aCanBubble, aCancelable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mData = aData;
|
||||
mozilla::HoldJSObjects(this);
|
||||
mOrigin = aOrigin;
|
||||
mLastEventId = aLastEventId;
|
||||
|
||||
mWindowSource = nullptr;
|
||||
mPortSource = nullptr;
|
||||
|
||||
if (!aSource.IsNull()) {
|
||||
if (aSource.Value().IsWindowProxy()) {
|
||||
mWindowSource = aSource.Value().GetAsWindowProxy();
|
||||
} else {
|
||||
mPortSource = &aSource.Value().GetAsMessagePort();
|
||||
}
|
||||
}
|
||||
|
||||
mPorts = nullptr;
|
||||
|
||||
if (!aPorts.IsNull()) {
|
||||
nsTArray<nsRefPtr<MessagePort>> ports;
|
||||
for (uint32_t i = 0, len = aPorts.Value().Length(); i < len; ++i) {
|
||||
ports.AppendElement(aPorts.Value()[i]);
|
||||
}
|
||||
|
||||
mPorts = new MessagePortList(static_cast<Event*>(this), ports);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessageEvent::SetPorts(MessagePortList* aPorts)
|
||||
{
|
||||
@ -227,7 +270,7 @@ using namespace mozilla::dom;
|
||||
already_AddRefed<MessageEvent>
|
||||
NS_NewDOMMessageEvent(EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent)
|
||||
WidgetEvent* aEvent)
|
||||
{
|
||||
nsRefPtr<MessageEvent> it = new MessageEvent(aOwner, aPresContext, aEvent);
|
||||
return it.forget();
|
||||
|
@ -8,9 +8,10 @@
|
||||
#define mozilla_dom_MessageEvent_h_
|
||||
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/MessagePortList.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMMessageEvent.h"
|
||||
#include "mozilla/dom/MessagePortList.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -19,6 +20,7 @@ struct MessageEventInit;
|
||||
class MessagePort;
|
||||
class MessagePortList;
|
||||
class OwningWindowProxyOrMessagePortOrClient;
|
||||
class WindowProxyOrMessagePort;
|
||||
|
||||
namespace workers {
|
||||
|
||||
@ -85,6 +87,13 @@ public:
|
||||
const MessageEventInit& aEventInit,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void InitMessageEvent(JSContext* aCx, const nsAString& aType, bool aCanBubble,
|
||||
bool aCancelable, JS::Handle<JS::Value> aData,
|
||||
const nsAString& aOrigin, const nsAString& aLastEventId,
|
||||
const Nullable<WindowProxyOrMessagePort>& aSource,
|
||||
const Nullable<Sequence<OwningNonNull<MessagePort>>>& aPorts,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
~MessageEvent();
|
||||
|
||||
|
@ -13,6 +13,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
function testMessageEvent(e, test) {
|
||||
ok(e, "MessageEvent created");
|
||||
is(e.type, 'message', 'MessageEvent.type is right');
|
||||
|
||||
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok');
|
||||
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
|
||||
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
|
||||
is(e.source, 'source' in test ? test.source : null, 'MessageEvent.source is ok');
|
||||
|
||||
if (test.ports != undefined) {
|
||||
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
|
||||
is(e.ports, e.ports, 'MessageEvent.ports is ok');
|
||||
} else {
|
||||
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
|
||||
}
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var channel = new MessageChannel();
|
||||
|
||||
@ -33,20 +50,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294
|
||||
var test = tests.shift();
|
||||
|
||||
var e = new MessageEvent('message', test);
|
||||
ok(e, "MessageEvent created");
|
||||
is(e.type, 'message', 'MessageEvent.type is right');
|
||||
testMessageEvent(e, test);
|
||||
|
||||
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok');
|
||||
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
|
||||
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
|
||||
is(e.source, 'source' in test ? test.source : null, 'MessageEvent.source is ok');
|
||||
|
||||
if (test.ports != undefined) {
|
||||
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
|
||||
is(e.ports, e.ports, 'MessageEvent.ports is ok');
|
||||
} else {
|
||||
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
|
||||
}
|
||||
e = new MessageEvent('message');
|
||||
e.initMessageEvent('message', true, true,
|
||||
'data' in test ? test.data : undefined,
|
||||
'origin' in test ? test.origin : '',
|
||||
'lastEventId' in test ? test.lastEventId : '',
|
||||
'source' in test ? test.source : null,
|
||||
'ports' in test ? test.ports : null);
|
||||
testMessageEvent(e, test);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/FetchDriver.h"
|
||||
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
@ -42,7 +43,7 @@ namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(FetchDriver,
|
||||
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
|
||||
nsIAsyncVerifyRedirectCallback, nsIThreadRetargetableStreamListener)
|
||||
nsIThreadRetargetableStreamListener)
|
||||
|
||||
FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup)
|
||||
@ -459,7 +460,13 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
|
||||
|
||||
// Insert ourselves into the notification callbacks chain so we can handle
|
||||
// cross-origin redirects.
|
||||
chan->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
|
||||
chan->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
|
||||
MOZ_ASSERT(!notificationCallbacks);
|
||||
}
|
||||
#endif
|
||||
chan->SetNotificationCallbacks(this);
|
||||
|
||||
// FIXME(nsm): Bug 1120715.
|
||||
@ -915,8 +922,6 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
{
|
||||
NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// HTTP Fetch step 5, "redirect status", step 1
|
||||
if (NS_WARN_IF(mRequest->GetRedirectMode() == RequestRedirect::Error)) {
|
||||
aOldChannel->Cancel(NS_BINDING_FAILED);
|
||||
@ -970,27 +975,85 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
// to a URL with credentials in CORS mode. This is implemented in
|
||||
// nsCORSListenerProxy.
|
||||
|
||||
mRedirectCallback = aCallback;
|
||||
mOldRedirectChannel = aOldChannel;
|
||||
mNewRedirectChannel = aNewChannel;
|
||||
// On a successful redirect we perform the following substeps of HTTP Fetch,
|
||||
// step 5, "redirect status", step 11.
|
||||
|
||||
nsCOMPtr<nsIChannelEventSink> outer =
|
||||
do_GetInterface(mNotificationCallbacks);
|
||||
if (outer) {
|
||||
// The callee is supposed to call OnRedirectVerifyCallback() on success,
|
||||
// and nobody has to call it on failure, so we can just return after this
|
||||
// block.
|
||||
rv = outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
aOldChannel->Cancel(rv);
|
||||
mRedirectCallback = nullptr;
|
||||
mOldRedirectChannel = nullptr;
|
||||
mNewRedirectChannel = nullptr;
|
||||
}
|
||||
// Step 11.5 "Append locationURL to request's url list." so that when we set the
|
||||
// Response's URL from the Request's URL in Main Fetch, step 15, we get the
|
||||
// final value. Note, we still use a single URL value instead of a list.
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
||||
if (NS_FAILED(rv)) {
|
||||
aOldChannel->Cancel(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
(void) OnRedirectVerifyCallback(NS_OK);
|
||||
// We need to update our request's URL.
|
||||
nsAutoCString newUrl;
|
||||
newURI->GetSpec(newUrl);
|
||||
mRequest->SetURL(newUrl);
|
||||
|
||||
// Implement Main Fetch step 8 again on redirect.
|
||||
MainFetchOp nextOp = SetTaintingAndGetNextOp(mCORSFlagEverSet);
|
||||
|
||||
if (nextOp.mType == NETWORK_ERROR) {
|
||||
// Cancel the channel if Main Fetch blocks the redirect from continuing.
|
||||
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
// Otherwise, we rely on necko and the CORS proxy to do the right thing
|
||||
// as the redirect is followed. In general this means basic or http
|
||||
// fetch. If we've ever been CORS, we need to stay CORS.
|
||||
MOZ_ASSERT(nextOp.mType == BASIC_FETCH || nextOp.mType == HTTP_FETCH);
|
||||
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mType == HTTP_FETCH);
|
||||
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mCORSFlag);
|
||||
|
||||
// Examine and possibly set the LOAD_ANONYMOUS flag on the channel.
|
||||
nsLoadFlags flags;
|
||||
rv = aNewChannel->GetLoadFlags(&flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
aOldChannel->Cancel(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
|
||||
mRequest->GetResponseTainting() == InternalRequest::RESPONSETAINT_OPAQUE) {
|
||||
// In the case of a "no-cors" mode request with "same-origin" credentials,
|
||||
// we have to set LOAD_ANONYMOUS manually here in order to avoid sending
|
||||
// credentials on a cross-origin redirect.
|
||||
flags |= nsIRequest::LOAD_ANONYMOUS;
|
||||
rv = aNewChannel->SetLoadFlags(flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
aOldChannel->Cancel(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Omit) {
|
||||
// Make sure nothing in the redirect chain screws up our credentials
|
||||
// settings. LOAD_ANONYMOUS must be set if we RequestCredentials is "omit".
|
||||
MOZ_ASSERT(flags & nsIRequest::LOAD_ANONYMOUS);
|
||||
|
||||
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
|
||||
nextOp.mCORSFlag) {
|
||||
// We also want to verify the LOAD_ANONYMOUS flag is set when we are in
|
||||
// "same-origin" credentials mode and the CORS flag is set. We can't
|
||||
// unconditionally assert here, however, because the nsCORSListenerProxy
|
||||
// will set the flag later in the redirect callback chain. Instead,
|
||||
// perform a weaker assertion here by checking if CORS flag was set
|
||||
// before this redirect. In that case LOAD_ANONYMOUS must still be set.
|
||||
MOZ_ASSERT_IF(mCORSFlagEverSet, flags & nsIRequest::LOAD_ANONYMOUS);
|
||||
|
||||
} else {
|
||||
// Otherwise, we should be sending credentials
|
||||
MOZ_ASSERT(!(flags & nsIRequest::LOAD_ANONYMOUS));
|
||||
}
|
||||
|
||||
// Track the CORSFlag through redirects.
|
||||
mCORSFlagEverSet = mCORSFlagEverSet || nextOp.mCORSFlag;
|
||||
|
||||
aCallback->OnRedirectVerifyCallback(NS_OK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1036,21 +1099,12 @@ FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mNotificationCallbacks) {
|
||||
rv = mNotificationCallbacks->GetInterface(aIID, aResult);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
|
||||
if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
|
||||
*aResult = static_cast<nsIStreamListener*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
else if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
|
||||
if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
|
||||
*aResult = static_cast<nsIRequestObserver*>(this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
@ -1059,90 +1113,6 @@ FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FetchDriver::OnRedirectVerifyCallback(nsresult aResult)
|
||||
{
|
||||
// On a successful redirect we perform the following substeps of HTTP Fetch,
|
||||
// step 5, "redirect status", step 11.
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
// Step 11.5 "Append locationURL to request's url list." so that when we set the
|
||||
// Response's URL from the Request's URL in Main Fetch, step 15, we get the
|
||||
// final value. Note, we still use a single URL value instead of a list.
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(mNewRedirectChannel, getter_AddRefs(newURI));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResult = rv;
|
||||
} else {
|
||||
// We need to update our request's URL.
|
||||
nsAutoCString newUrl;
|
||||
newURI->GetSpec(newUrl);
|
||||
mRequest->SetURL(newUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
mOldRedirectChannel->Cancel(aResult);
|
||||
}
|
||||
|
||||
// Implement Main Fetch step 8 again on redirect.
|
||||
MainFetchOp nextOp = SetTaintingAndGetNextOp(mCORSFlagEverSet);
|
||||
|
||||
if (nextOp.mType == NETWORK_ERROR) {
|
||||
// Cancel the channel if Main Fetch blocks the redirect from continuing.
|
||||
aResult = NS_ERROR_DOM_BAD_URI;
|
||||
mOldRedirectChannel->Cancel(aResult);
|
||||
} else {
|
||||
// Otherwise, we rely on necko and the CORS proxy to do the right thing
|
||||
// as the redirect is followed. In general this means basic or http
|
||||
// fetch. If we've ever been CORS, we need to stay CORS.
|
||||
MOZ_ASSERT(nextOp.mType == BASIC_FETCH || nextOp.mType == HTTP_FETCH);
|
||||
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mType == HTTP_FETCH);
|
||||
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mCORSFlag);
|
||||
|
||||
// Examine and possibly set the LOAD_ANONYMOUS flag on the channel.
|
||||
nsLoadFlags flags;
|
||||
aResult = mNewRedirectChannel->GetLoadFlags(&flags);
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
|
||||
mRequest->GetResponseTainting() == InternalRequest::RESPONSETAINT_OPAQUE) {
|
||||
// In the case of a "no-cors" mode request with "same-origin" credentials,
|
||||
// we have to set LOAD_ANONYMOUS manually here in order to avoid sending
|
||||
// credentials on a cross-origin redirect.
|
||||
flags |= nsIRequest::LOAD_ANONYMOUS;
|
||||
aResult = mNewRedirectChannel->SetLoadFlags(flags);
|
||||
|
||||
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Omit) {
|
||||
// Make sure nothing in the redirect chain screws up our credentials
|
||||
// settings. LOAD_ANONYMOUS must be set if we RequestCredentials is "omit".
|
||||
MOZ_ASSERT(flags & nsIRequest::LOAD_ANONYMOUS);
|
||||
|
||||
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
|
||||
nextOp.mCORSFlag) {
|
||||
// We also want to verify the LOAD_ANONYMOUS flag is set when we are in
|
||||
// "same-origin" credentials mode and the CORS flag is set. We can't
|
||||
// unconditionally assert here, however, because the nsCORSListenerProxy
|
||||
// will set the flag later in the redirect callback chain. Instead,
|
||||
// perform a weaker assertion here by checking if CORS flag was set
|
||||
// before this redirect. In that case LOAD_ANONYMOUS must still be set.
|
||||
MOZ_ASSERT_IF(mCORSFlagEverSet, flags & nsIRequest::LOAD_ANONYMOUS);
|
||||
|
||||
} else {
|
||||
// Otherwise, we should be sending credentials
|
||||
MOZ_ASSERT(!(flags & nsIRequest::LOAD_ANONYMOUS));
|
||||
}
|
||||
}
|
||||
|
||||
// Track the CORSFlag through redirects.
|
||||
mCORSFlagEverSet = mCORSFlagEverSet || nextOp.mCORSFlag;
|
||||
}
|
||||
|
||||
mOldRedirectChannel = nullptr;
|
||||
mNewRedirectChannel = nullptr;
|
||||
mRedirectCallback->OnRedirectVerifyCallback(aResult);
|
||||
mRedirectCallback = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FetchDriver::SetDocument(nsIDocument* aDocument)
|
||||
{
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define mozilla_dom_FetchDriver_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIStreamListener.h"
|
||||
@ -58,7 +57,6 @@ private:
|
||||
class FetchDriver final : public nsIStreamListener,
|
||||
public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIAsyncVerifyRedirectCallback,
|
||||
public nsIThreadRetargetableStreamListener
|
||||
{
|
||||
public:
|
||||
@ -67,7 +65,6 @@ public:
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
|
||||
explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
|
||||
@ -84,10 +81,6 @@ private:
|
||||
nsRefPtr<InternalResponse> mResponse;
|
||||
nsCOMPtr<nsIOutputStream> mPipeOutputStream;
|
||||
nsRefPtr<FetchDriverObserver> mObserver;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
|
||||
nsCOMPtr<nsIChannel> mOldRedirectChannel;
|
||||
nsCOMPtr<nsIChannel> mNewRedirectChannel;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
uint32_t mFetchRecursionCount;
|
||||
bool mCORSFlagEverSet;
|
||||
|
@ -1443,6 +1443,7 @@ TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
|
||||
a11y::DocAccessibleParent*
|
||||
TabParent::GetTopLevelDocAccessible() const
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
// XXX Consider managing non top level PDocAccessibles with their parent
|
||||
// document accessible.
|
||||
const nsTArray<PDocAccessibleParent*>& docs = ManagedPDocAccessibleParent();
|
||||
@ -1453,7 +1454,7 @@ TabParent::GetTopLevelDocAccessible() const
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,9 @@ class nsIDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace a11y {
|
||||
namespace a11y {
|
||||
class DocAccessibleParent;
|
||||
}
|
||||
}
|
||||
|
||||
namespace jsipc {
|
||||
class CpowHolder;
|
||||
@ -266,7 +266,7 @@ public:
|
||||
/**
|
||||
* Return the top level doc accessible parent for this tab.
|
||||
*/
|
||||
a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
|
||||
a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
|
||||
|
||||
void LoadURL(nsIURI* aURI);
|
||||
// XXX/cjones: it's not clear what we gain by hiding these
|
||||
|
@ -849,6 +849,10 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
(video ? video->GetEndTime() : -1),
|
||||
(video ? video->mDiscontinuity : 0));
|
||||
|
||||
// Check frame validity here for every decoded frame in order to have a
|
||||
// better chance to make the decision of turning off HW acceleration.
|
||||
CheckFrameValidity(aVideoSample->As<VideoData>());
|
||||
|
||||
switch (mState) {
|
||||
case DECODER_STATE_BUFFERING: {
|
||||
// If we're buffering, this may be the sample we need to stop buffering.
|
||||
@ -2448,16 +2452,11 @@ MediaDecoderStateMachine::Reset()
|
||||
DecodeTaskQueue()->Dispatch(resetTask.forget());
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
|
||||
void
|
||||
MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
// If we've sent this frame before then only return the valid state,
|
||||
// don't update the statistics.
|
||||
if (aData->mSentToCompositor) {
|
||||
return !aData->mImage || aData->mImage->IsValid();
|
||||
}
|
||||
|
||||
// Update corrupt-frames statistics
|
||||
if (aData->mImage && !aData->mImage->IsValid()) {
|
||||
FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
|
||||
@ -2475,10 +2474,8 @@ bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
|
||||
mCorruptFrames.clear();
|
||||
gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA";
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
mCorruptFrames.insert(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2500,7 +2497,7 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames,
|
||||
for (uint32_t i = 0; i < frames.Length(); ++i) {
|
||||
VideoData* frame = frames[i]->As<VideoData>();
|
||||
|
||||
bool valid = CheckFrameValidity(frame);
|
||||
bool valid = !frame->mImage || frame->mImage->IsValid();
|
||||
frame->mSentToCompositor = true;
|
||||
|
||||
if (!valid) {
|
||||
|
@ -463,8 +463,9 @@ protected:
|
||||
// machine thread, caller must hold the decoder lock.
|
||||
void UpdatePlaybackPositionInternal(int64_t aTime);
|
||||
|
||||
// Decode monitor must be held.
|
||||
bool CheckFrameValidity(VideoData* aData);
|
||||
// Decode monitor must be held. To determine if MDSM needs to turn off HW
|
||||
// acceleration.
|
||||
void CheckFrameValidity(VideoData* aData);
|
||||
|
||||
// Sets VideoQueue images into the VideoFrameContainer. Called on the shared
|
||||
// state machine thread. Decode monitor must be held. The first aMaxFrames
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s || buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
|
||||
support-files =
|
||||
mediasource.js
|
||||
seek.webm seek.webm^headers^
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
return mPorts[aIndex];
|
||||
}
|
||||
|
||||
public:
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsTArray<nsRefPtr<MessagePort>> mPorts;
|
||||
};
|
||||
|
@ -44,6 +44,12 @@ interface MessageEvent : Event {
|
||||
* data, origin, source, and lastEventId attributes of this appropriately.
|
||||
*/
|
||||
readonly attribute MessagePortList? ports;
|
||||
|
||||
[Throws]
|
||||
void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable,
|
||||
any data, DOMString origin, DOMString lastEventId,
|
||||
(WindowProxy or MessagePort)? source,
|
||||
sequence<MessagePort>? ports);
|
||||
};
|
||||
|
||||
dictionary MessageEventInit : EventInit {
|
||||
|
@ -6393,25 +6393,25 @@ nsHTMLEditRules::ReturnInHeader(Selection* aSelection,
|
||||
nsIDOMNode *aNode,
|
||||
int32_t aOffset)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSelection && aHeader && aNode, NS_ERROR_NULL_POINTER);
|
||||
nsCOMPtr<Element> header = do_QueryInterface(aHeader);
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
||||
NS_ENSURE_TRUE(aSelection && header && node, NS_ERROR_NULL_POINTER);
|
||||
|
||||
// remeber where the header is
|
||||
int32_t offset;
|
||||
nsCOMPtr<nsIDOMNode> headerParent = nsEditor::GetNodeLocation(aHeader, &offset);
|
||||
|
||||
// get ws code to adjust any ws
|
||||
nsCOMPtr<nsINode> selNode(do_QueryInterface(aNode));
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsresult res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor,
|
||||
address_of(selNode),
|
||||
address_of(node),
|
||||
&aOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// split the header
|
||||
int32_t newOffset;
|
||||
NS_ENSURE_STATE(node->IsContent());
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
res = mHTMLEditor->SplitNodeDeep(aHeader, GetAsDOMNode(selNode), aOffset, &newOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
mHTMLEditor->SplitNodeDeep(*header, *node->AsContent(), aOffset);
|
||||
|
||||
// if the leftand heading is empty, put a mozbr in it
|
||||
nsCOMPtr<nsIDOMNode> prevItem;
|
||||
@ -6598,13 +6598,14 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
|
||||
nsCOMPtr<nsIDOMNode> *aSelNode,
|
||||
int32_t *aOffset)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPara && aBRNode && aSelNode && *aSelNode && aOffset && aSelection, NS_ERROR_NULL_POINTER);
|
||||
nsCOMPtr<Element> para = do_QueryInterface(aPara);
|
||||
NS_ENSURE_TRUE(para && aBRNode && aSelNode && *aSelNode && aOffset &&
|
||||
aSelection, NS_ERROR_NULL_POINTER);
|
||||
nsresult res = NS_OK;
|
||||
|
||||
// split para
|
||||
int32_t newOffset;
|
||||
// get ws code to adjust any ws
|
||||
nsCOMPtr<nsIDOMNode> leftPara, rightPara;
|
||||
nsCOMPtr<nsIContent> leftPara, rightPara;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<nsINode> selNode(do_QueryInterface(*aSelNode));
|
||||
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), aOffset);
|
||||
@ -6612,9 +6613,11 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// split the paragraph
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
res = mHTMLEditor->SplitNodeDeep(aPara, *aSelNode, *aOffset, &newOffset, false,
|
||||
address_of(leftPara), address_of(rightPara));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
NS_ENSURE_STATE(selNode->IsContent());
|
||||
mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset,
|
||||
nsHTMLEditor::EmptyContainers::yes,
|
||||
getter_AddRefs(leftPara),
|
||||
getter_AddRefs(rightPara));
|
||||
// get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p)
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
if (mHTMLEditor->IsVisBreak(aBRNode))
|
||||
@ -6631,9 +6634,9 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// check both halves of para to see if we need mozBR
|
||||
res = InsertMozBRIfNeeded(leftPara);
|
||||
res = InsertMozBRIfNeeded(GetAsDOMNode(leftPara));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = InsertMozBRIfNeeded(rightPara);
|
||||
res = InsertMozBRIfNeeded(GetAsDOMNode(rightPara));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// selection to beginning of right hand para;
|
||||
@ -6751,10 +6754,9 @@ nsHTMLEditRules::ReturnInListItem(Selection* aSelection,
|
||||
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// now split list item
|
||||
int32_t newOffset;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
res = mHTMLEditor->SplitNodeDeep(aListItem, GetAsDOMNode(selNode), aOffset, &newOffset, false);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
NS_ENSURE_STATE(selNode->IsContent());
|
||||
mHTMLEditor->SplitNodeDeep(*listItem, *selNode->AsContent(), aOffset);
|
||||
// hack: until I can change the damaged doc range code back to being
|
||||
// extra inclusive, I have to manually detect certain list items that
|
||||
// may be left empty.
|
||||
@ -7156,14 +7158,15 @@ nsHTMLEditRules::SplitAsNeeded(nsIAtom& aTag,
|
||||
// Could not find a place to build tag!
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (splitNode) {
|
||||
if (splitNode && splitNode->IsContent() && inOutParent->IsContent()) {
|
||||
// We found a place for block, but above inOutParent. We need to split.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsresult res = mHTMLEditor->SplitNodeDeep(splitNode->AsDOMNode(),
|
||||
inOutParent->AsDOMNode(),
|
||||
inOutOffset, &inOutOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
int32_t offset = mHTMLEditor->SplitNodeDeep(*splitNode->AsContent(),
|
||||
*inOutParent->AsContent(),
|
||||
inOutOffset);
|
||||
NS_ENSURE_STATE(offset != -1);
|
||||
inOutParent = tagParent;
|
||||
inOutOffset = offset;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1583,10 +1583,10 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode,
|
||||
NS_ENSURE_TRUE(ioOffset, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsINode> parent = do_QueryInterface(*ioParent);
|
||||
nsCOMPtr<nsIContent> parent = do_QueryInterface(*ioParent);
|
||||
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
|
||||
nsCOMPtr<nsINode> topChild = parent;
|
||||
int32_t offsetOfInsert = *ioOffset;
|
||||
nsCOMPtr<nsIContent> topChild = parent;
|
||||
nsCOMPtr<nsIContent> origParent = parent;
|
||||
|
||||
// Search up the parent chain to find a suitable container
|
||||
while (!CanContain(*parent, *node)) {
|
||||
@ -1602,24 +1602,24 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode,
|
||||
// There's no suitable place to put the node in this editing host. Maybe
|
||||
// someone is trying to put block content in a span. So just put it
|
||||
// where we were originally asked.
|
||||
parent = topChild = do_QueryInterface(*ioParent);
|
||||
NS_ENSURE_STATE(parent);
|
||||
parent = topChild = origParent;
|
||||
break;
|
||||
}
|
||||
topChild = parent;
|
||||
parent = parent->GetParentNode();
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
if (parent != topChild)
|
||||
{
|
||||
// we need to split some levels above the original selection parent
|
||||
res = SplitNodeDeep(GetAsDOMNode(topChild), *ioParent, *ioOffset,
|
||||
&offsetOfInsert, aNoEmptyNodes);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
int32_t offset = SplitNodeDeep(*topChild, *origParent, *ioOffset,
|
||||
aNoEmptyNodes ? EmptyContainers::no
|
||||
: EmptyContainers::yes);
|
||||
NS_ENSURE_STATE(offset != -1);
|
||||
*ioParent = GetAsDOMNode(parent);
|
||||
*ioOffset = offsetOfInsert;
|
||||
*ioOffset = offset;
|
||||
}
|
||||
// Now we can insert the new node
|
||||
res = InsertNode(*node, *parent, offsetOfInsert);
|
||||
res = InsertNode(*node, *parent, *ioOffset);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1927,30 +1927,31 @@ nsHTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList, cons
|
||||
// Find out if the selection is collapsed:
|
||||
bool isCollapsed = selection->Collapsed();
|
||||
|
||||
nsCOMPtr<nsINode> node;
|
||||
int32_t offset;
|
||||
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
|
||||
if (!node) res = NS_ERROR_FAILURE;
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
|
||||
selection->GetRangeAt(0)->GetStartParent() &&
|
||||
selection->GetRangeAt(0)->GetStartParent()->IsContent(),
|
||||
NS_ERROR_FAILURE);
|
||||
OwningNonNull<nsIContent> node =
|
||||
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
|
||||
int32_t offset = selection->GetRangeAt(0)->StartOffset();
|
||||
|
||||
if (isCollapsed)
|
||||
{
|
||||
// have to find a place to put the list
|
||||
nsCOMPtr<nsINode> parent = node;
|
||||
nsCOMPtr<nsINode> topChild = node;
|
||||
nsCOMPtr<nsIContent> parent = node;
|
||||
nsCOMPtr<nsIContent> topChild = node;
|
||||
|
||||
nsCOMPtr<nsIAtom> listAtom = do_GetAtom(aListType);
|
||||
while (!CanContainTag(*parent, *listAtom)) {
|
||||
topChild = parent;
|
||||
parent = parent->GetParentNode();
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
|
||||
if (parent != node)
|
||||
{
|
||||
// we need to split up to the child of parent
|
||||
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset,
|
||||
&offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
offset = SplitNodeDeep(*topChild, *node, offset);
|
||||
NS_ENSURE_STATE(offset != -1);
|
||||
}
|
||||
|
||||
// make a list
|
||||
@ -2058,31 +2059,32 @@ nsHTMLEditor::InsertBasicBlock(const nsAString& aBlockType)
|
||||
// Find out if the selection is collapsed:
|
||||
bool isCollapsed = selection->Collapsed();
|
||||
|
||||
nsCOMPtr<nsINode> node;
|
||||
int32_t offset;
|
||||
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
|
||||
if (!node) res = NS_ERROR_FAILURE;
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
|
||||
selection->GetRangeAt(0)->GetStartParent() &&
|
||||
selection->GetRangeAt(0)->GetStartParent()->IsContent(),
|
||||
NS_ERROR_FAILURE);
|
||||
OwningNonNull<nsIContent> node =
|
||||
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
|
||||
int32_t offset = selection->GetRangeAt(0)->StartOffset();
|
||||
|
||||
if (isCollapsed)
|
||||
{
|
||||
// have to find a place to put the block
|
||||
nsCOMPtr<nsINode> parent = node;
|
||||
nsCOMPtr<nsINode> topChild = node;
|
||||
nsCOMPtr<nsIContent> parent = node;
|
||||
nsCOMPtr<nsIContent> topChild = node;
|
||||
|
||||
nsCOMPtr<nsIAtom> blockAtom = do_GetAtom(aBlockType);
|
||||
while (!CanContainTag(*parent, *blockAtom)) {
|
||||
NS_ENSURE_TRUE(parent->GetParentNode(), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(parent->GetParent(), NS_ERROR_FAILURE);
|
||||
topChild = parent;
|
||||
parent = parent->GetParentNode();
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
|
||||
if (parent != node)
|
||||
{
|
||||
// we need to split up to the child of parent
|
||||
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset,
|
||||
&offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
offset = SplitNodeDeep(*topChild, *node, offset);
|
||||
NS_ENSURE_STATE(offset != -1);
|
||||
}
|
||||
|
||||
// make a block
|
||||
@ -2128,33 +2130,34 @@ nsHTMLEditor::Indent(const nsAString& aIndent)
|
||||
if (!handled)
|
||||
{
|
||||
// Do default - insert a blockquote node if selection collapsed
|
||||
nsCOMPtr<nsINode> node;
|
||||
int32_t offset;
|
||||
bool isCollapsed = selection->Collapsed();
|
||||
|
||||
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
|
||||
if (!node) res = NS_ERROR_FAILURE;
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
|
||||
selection->GetRangeAt(0)->GetStartParent() &&
|
||||
selection->GetRangeAt(0)->GetStartParent()->IsContent(),
|
||||
NS_ERROR_FAILURE);
|
||||
OwningNonNull<nsIContent> node =
|
||||
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
|
||||
int32_t offset = selection->GetRangeAt(0)->StartOffset();
|
||||
|
||||
if (aIndent.EqualsLiteral("indent"))
|
||||
{
|
||||
if (isCollapsed)
|
||||
{
|
||||
// have to find a place to put the blockquote
|
||||
nsCOMPtr<nsINode> parent = node;
|
||||
nsCOMPtr<nsINode> topChild = node;
|
||||
nsCOMPtr<nsIContent> parent = node;
|
||||
nsCOMPtr<nsIContent> topChild = node;
|
||||
while (!CanContainTag(*parent, *nsGkAtoms::blockquote)) {
|
||||
NS_ENSURE_TRUE(parent->GetParentNode(), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(parent->GetParent(), NS_ERROR_FAILURE);
|
||||
topChild = parent;
|
||||
parent = parent->GetParentNode();
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
|
||||
if (parent != node)
|
||||
{
|
||||
// we need to split up to the child of parent
|
||||
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node),
|
||||
offset, &offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
offset = SplitNodeDeep(*topChild, *node, offset);
|
||||
NS_ENSURE_STATE(offset != -1);
|
||||
}
|
||||
|
||||
// make a blockquote
|
||||
@ -2166,9 +2169,9 @@ nsHTMLEditor::Indent(const nsAString& aIndent)
|
||||
res = InsertText(NS_LITERAL_STRING(" "));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// reposition selection to before the space character
|
||||
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = selection->Collapse(node,0);
|
||||
NS_ENSURE_STATE(selection->GetRangeAt(0));
|
||||
res = selection->Collapse(selection->GetRangeAt(0)->GetStartParent(),
|
||||
0);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
}
|
||||
|
@ -592,12 +592,22 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
|
||||
// or the style is specified in the style attribute
|
||||
isSet) {
|
||||
// found a style node we need to split
|
||||
nsresult rv = SplitNodeDeep(GetAsDOMNode(node), *aNode, *aOffset,
|
||||
&offset, false, outLeftNode, outRightNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIContent> outLeftContent, outRightContent;
|
||||
nsCOMPtr<nsIContent> nodeParam = do_QueryInterface(*aNode);
|
||||
NS_ENSURE_STATE(nodeParam || !*aNode);
|
||||
offset = SplitNodeDeep(*node, *nodeParam, *aOffset, EmptyContainers::yes,
|
||||
getter_AddRefs(outLeftContent),
|
||||
getter_AddRefs(outRightContent));
|
||||
NS_ENSURE_TRUE(offset != -1, NS_ERROR_FAILURE);
|
||||
// reset startNode/startOffset
|
||||
*aNode = GetAsDOMNode(node->GetParent());
|
||||
*aOffset = offset;
|
||||
if (outLeftNode) {
|
||||
*outLeftNode = GetAsDOMNode(outLeftContent);
|
||||
}
|
||||
if (outRightNode) {
|
||||
*outRightNode = GetAsDOMNode(outRightContent);
|
||||
}
|
||||
}
|
||||
node = node->GetParent();
|
||||
}
|
||||
|
@ -837,20 +837,18 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
|
||||
aSize.width, aSize.height,
|
||||
GfxFormatToSkiaColorType(aFormat),
|
||||
alphaType);
|
||||
// we need to have surfaces that have a stride aligned to 4 for interop with cairo
|
||||
int stride = (BytesPerPixel(aFormat)*aSize.width + (4-1)) & -4;
|
||||
|
||||
SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(skiInfo));
|
||||
if (!device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkBitmap bitmap = device->accessBitmap(true);
|
||||
SkBitmap bitmap;
|
||||
bitmap.setInfo(skiInfo, stride);
|
||||
if (!bitmap.allocPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bitmap.eraseARGB(0, 0, 0, 0);
|
||||
|
||||
mCanvas.adopt(new SkCanvas(device.get()));
|
||||
mCanvas.adopt(new SkCanvas(bitmap));
|
||||
mSize = aSize;
|
||||
|
||||
mFormat = aFormat;
|
||||
|
@ -64,6 +64,11 @@ SourceSurfaceD2DTarget::GetDataSurface()
|
||||
desc.BindFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
if (!Factory::GetDirect3D10Device()) {
|
||||
gfxCriticalError() << "Invalid D3D10 device in D2D target surface";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
|
@ -1352,6 +1352,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
SymLoadStruct mapBufferRangeSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
|
@ -734,6 +734,16 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
|
||||
}
|
||||
}
|
||||
|
||||
static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
|
||||
SkASSERT(matrix.rectStaysRect());
|
||||
SkASSERT(SkPaint::kFill_Style != paint.getStyle());
|
||||
|
||||
SkVector size;
|
||||
SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
|
||||
matrix.mapVectors(&size, &pt, 1);
|
||||
return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
|
||||
}
|
||||
|
||||
static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
|
||||
SkPoint* strokeSize) {
|
||||
if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
|
||||
@ -812,12 +822,22 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
|
||||
devRect.sort();
|
||||
|
||||
// look for the quick exit, before we build a blitter
|
||||
SkIRect ir;
|
||||
devRect.roundOut(&ir);
|
||||
SkRect bbox = devRect;
|
||||
if (paint.getStyle() != SkPaint::kFill_Style) {
|
||||
// extra space for hairlines
|
||||
ir.inset(-1, -1);
|
||||
if (paint.getStrokeWidth() == 0) {
|
||||
bbox.outset(1, 1);
|
||||
} else {
|
||||
// For kStroke_RectType, strokeSize is already computed.
|
||||
const SkPoint& ssize = (kStroke_RectType == rtype)
|
||||
? strokeSize
|
||||
: compute_stroke_size(paint, *fMatrix);
|
||||
bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
|
||||
}
|
||||
}
|
||||
|
||||
SkIRect ir;
|
||||
bbox.roundOut(&ir);
|
||||
if (fRC->quickReject(ir)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2157,13 +2157,9 @@ gfxPlatform::PerfWarnings()
|
||||
return gfxPrefs::PerfWarnings();
|
||||
}
|
||||
|
||||
void
|
||||
gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
|
||||
static inline bool
|
||||
AllowOpenGL(bool* aWhitelisted)
|
||||
{
|
||||
// Being whitelisted is not enough to accelerate, but not being whitelisted is
|
||||
// enough not to:
|
||||
bool whitelisted = false;
|
||||
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
|
||||
if (gfxInfo) {
|
||||
// bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
|
||||
@ -2175,12 +2171,26 @@ gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
|
||||
if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
|
||||
whitelisted = true;
|
||||
*aWhitelisted = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gfxPrefs::LayersAccelerationForceEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
|
||||
{
|
||||
// Being whitelisted is not enough to accelerate, but not being whitelisted is
|
||||
// enough not to:
|
||||
bool whitelisted = false;
|
||||
|
||||
if (AllowOpenGL(&whitelisted)) {
|
||||
aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
|
||||
}
|
||||
|
||||
if (!whitelisted) {
|
||||
static int tell_me_once = 0;
|
||||
if (!tell_me_once) {
|
||||
|
@ -1967,6 +1967,10 @@ gfxWindowsPlatform::CheckD3D11Support(bool* aCanUseHardware)
|
||||
*aCanUseHardware = false;
|
||||
return FeatureStatus::Available;
|
||||
}
|
||||
if (gfxPrefs::LayersAccelerationForceEnabled()) {
|
||||
*aCanUseHardware = true;
|
||||
return FeatureStatus::Available;
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
|
||||
int32_t status;
|
||||
|
@ -1792,6 +1792,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH();
|
||||
void* callee = nullptr;
|
||||
(void)callerRetAddr;
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
|
||||
void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
|
||||
@ -1817,6 +1818,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always);
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
(void)newCallee;
|
||||
MOZ_CRASH();
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
Assembler::WriteLuiOriInstructions(instr, instr->next(),
|
||||
@ -1882,6 +1884,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
||||
new (jump) InstNOP();
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
(void)jump;
|
||||
(void)profilingEpilogue;
|
||||
MOZ_CRASH();
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
Instruction* instr = (Instruction*)jump;
|
||||
|
@ -3111,13 +3111,20 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
case PNK_NEW:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
{
|
||||
ParseNode* next = pn->pn_head;
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
|
||||
|
||||
RootedValue callee(cx);
|
||||
if (!expression(next, &callee))
|
||||
return false;
|
||||
if (pn->isKind(PNK_SUPERCALL)) {
|
||||
MOZ_ASSERT(next->isKind(PNK_POSHOLDER));
|
||||
if (!builder.super(&next->pn_pos, &callee))
|
||||
return false;
|
||||
} else {
|
||||
if (!expression(next, &callee))
|
||||
return false;
|
||||
}
|
||||
|
||||
NodeVector args(cx);
|
||||
if (!args.reserve(pn->pn_count - 1))
|
||||
@ -3135,6 +3142,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
if (pn->getKind() == PNK_TAGGED_TEMPLATE)
|
||||
return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
|
||||
|
||||
// SUPERCALL is Call(super, args)
|
||||
return pn->isKind(PNK_NEW)
|
||||
? builder.newExpression(callee, args, &pn->pn_pos, dst)
|
||||
|
||||
|
@ -868,7 +868,7 @@ SetSavedStacksRNGState(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToInt32(cx, args[0], &seed))
|
||||
return false;
|
||||
|
||||
cx->compartment()->savedStacks().setRNGState((seed ^ RNG_MULTIPLIER) & RNG_MASK);
|
||||
cx->compartment()->savedStacks().setRNGState(seed, seed * 33);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1934,7 +1934,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
case PNK_TRUE:
|
||||
case PNK_FALSE:
|
||||
case PNK_NULL:
|
||||
case PNK_THIS:
|
||||
case PNK_ELISION:
|
||||
case PNK_GENERATOR:
|
||||
case PNK_NUMBER:
|
||||
@ -1943,6 +1942,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
*answer = false;
|
||||
return true;
|
||||
|
||||
// |this| can throw in derived class constructors.
|
||||
case PNK_THIS:
|
||||
MOZ_ASSERT(pn->isArity(PN_NULLARY));
|
||||
*answer = sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
|
||||
return true;
|
||||
|
||||
// Trivial binary nodes with more token pos holders.
|
||||
case PNK_NEWTARGET:
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
@ -2185,6 +2190,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_SUPERCALL:
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
*answer = true;
|
||||
return true;
|
||||
@ -6727,6 +6733,12 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
}
|
||||
callop = false;
|
||||
break;
|
||||
case PNK_POSHOLDER:
|
||||
MOZ_ASSERT(pn->isKind(PNK_SUPERCALL));
|
||||
MOZ_ASSERT(parser->handler.isSuperBase(pn2, cx));
|
||||
if (!emit1(JSOP_SUPERFUN))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
if (!emitTree(pn2))
|
||||
return false;
|
||||
@ -6739,7 +6751,8 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW;
|
||||
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
|
||||
pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;;
|
||||
|
||||
/*
|
||||
* Emit code for each argument in order, then emit the JSOP_*CALL or
|
||||
@ -6755,17 +6768,27 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
}
|
||||
|
||||
if (isNewOp) {
|
||||
// Repush the callee as new.target
|
||||
if (!emitDupAt(argc + 1))
|
||||
return false;
|
||||
if (pn->isKind(PNK_SUPERCALL)) {
|
||||
if (!emit1(JSOP_NEWTARGET))
|
||||
return false;
|
||||
} else {
|
||||
// Repush the callee as new.target
|
||||
if (!emitDupAt(argc + 1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
|
||||
return false;
|
||||
|
||||
if (isNewOp) {
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
if (pn->isKind(PNK_SUPERCALL)) {
|
||||
if (!emit1(JSOP_NEWTARGET))
|
||||
return false;
|
||||
} else {
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
emittingForInit = oldEmittingForInit;
|
||||
@ -6791,6 +6814,9 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pn->isKind(PNK_SUPERCALL) && !emit1(JSOP_SETTHIS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -7847,6 +7873,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_SUPERCALL:
|
||||
ok = emitCallOrNew(pn);
|
||||
break;
|
||||
|
||||
|
@ -414,6 +414,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
||||
case PNK_CLASSNAMES:
|
||||
case PNK_NEWTARGET:
|
||||
case PNK_POSHOLDER:
|
||||
case PNK_SUPERCALL:
|
||||
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
|
||||
"some parent node without recurring to test this node");
|
||||
|
||||
@ -1579,7 +1580,8 @@ static bool
|
||||
FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
|
||||
bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_TAGGED_TEMPLATE));
|
||||
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_SUPERCALL) ||
|
||||
node->isKind(PNK_TAGGED_TEMPLATE));
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
|
||||
// Don't fold a parenthesized callable component in an invocation, as this
|
||||
@ -1876,6 +1878,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
||||
return FoldAdd(cx, pnp, parser, inGenexpLambda);
|
||||
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
return FoldCall(cx, pn, parser, inGenexpLambda);
|
||||
|
||||
|
@ -376,6 +376,7 @@ class NameResolver
|
||||
case PNK_EXPORT_BATCH_SPEC:
|
||||
case PNK_FRESHENBLOCK:
|
||||
case PNK_OBJECT_PROPERTY_NAME:
|
||||
case PNK_POSHOLDER:
|
||||
MOZ_ASSERT(cur->isArity(PN_NULLARY));
|
||||
break;
|
||||
|
||||
@ -673,6 +674,7 @@ class NameResolver
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAY:
|
||||
case PNK_STATEMENTLIST:
|
||||
@ -796,7 +798,6 @@ class NameResolver
|
||||
case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
|
||||
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
|
||||
case PNK_CLASSNAMES: // by PNK_CLASS
|
||||
case PNK_POSHOLDER: // by PNK_NEWTARGET, PNK_DOT
|
||||
MOZ_CRASH("should have been handled by a parent node");
|
||||
|
||||
case PNK_LIMIT: // invalid sentinel value
|
||||
|
@ -489,6 +489,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAY:
|
||||
case PNK_OBJECT:
|
||||
|
@ -175,6 +175,7 @@ class PackedScopeCoordinate
|
||||
F(CLASSNAMES) \
|
||||
F(NEWTARGET) \
|
||||
F(POSHOLDER) \
|
||||
F(SUPERCALL) \
|
||||
\
|
||||
/* Unary operators. */ \
|
||||
F(TYPEOFNAME) \
|
||||
|
@ -8648,9 +8648,31 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
|
||||
tt == TOK_NO_SUBS_TEMPLATE)
|
||||
{
|
||||
if (handler.isSuperBase(lhs, context)) {
|
||||
// For now...
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPER);
|
||||
return null();
|
||||
if (!pc->sc->isFunctionBox() || !pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
|
||||
return null();
|
||||
}
|
||||
|
||||
if (tt != TOK_LP) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPER);
|
||||
return null();
|
||||
}
|
||||
|
||||
nextMember = handler.newList(PNK_SUPERCALL, lhs, JSOP_SUPERCALL);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
|
||||
// Despite the fact that it's impossible to have |super()| is a
|
||||
// generator, we still inherity the yieldHandling of the
|
||||
// memberExpression, per spec. Curious.
|
||||
bool isSpread = false;
|
||||
if (!argumentList(yieldHandling, nextMember, &isSpread))
|
||||
return null();
|
||||
|
||||
if (isSpread)
|
||||
handler.setOp(nextMember, JSOP_SPREADSUPERCALL);
|
||||
|
||||
return nextMember;
|
||||
}
|
||||
|
||||
nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
|
||||
|
@ -374,6 +374,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
hasExtensibleScope() ||
|
||||
needsDeclEnvObject() ||
|
||||
needsHomeObject() ||
|
||||
isDerivedClassConstructor() ||
|
||||
isGenerator();
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// |jit-test| error:InternalError
|
||||
// |jit-test| error:TypeError
|
||||
|
||||
// Binary: cache/js-dbg-32-4ce3983a43f4-linux
|
||||
// Flags:
|
||||
|
@ -1,13 +1,15 @@
|
||||
// |jit-test| error: ExitCleanly
|
||||
|
||||
assertEq((new (Proxy.createFunction({},
|
||||
var handler = { getPropertyDescriptor() { return undefined; } }
|
||||
|
||||
assertEq((new (Proxy.createFunction(handler,
|
||||
function(){ this.x = 1 },
|
||||
function(){ this.x = 2 }))).x, 2);
|
||||
// proxies can return the callee
|
||||
var x = Proxy.createFunction({}, function (q) { return q; });
|
||||
var x = Proxy.createFunction(handler, function (q) { return q; });
|
||||
assertEq(new x(x), x);
|
||||
try {
|
||||
var x = (Proxy.createFunction({}, "".indexOf));
|
||||
var x = (Proxy.createFunction(handler, "".indexOf));
|
||||
new x;
|
||||
throw "Should not be reached"
|
||||
}
|
||||
|
@ -32,5 +32,5 @@ dbg.memory.trackingAllocationSites = true;
|
||||
// probability is fine.
|
||||
measure(0.0, 0);
|
||||
measure(1.0, 100);
|
||||
measure(0.1, 9);
|
||||
measure(0.5, 51);
|
||||
measure(0.1, 7);
|
||||
measure(0.5, 44);
|
||||
|
@ -6,18 +6,3 @@ evalcx("\
|
||||
f();\
|
||||
f();\
|
||||
", newGlobal());
|
||||
|
||||
// Test 2: Don't take the prototype of proxy's to create |this|,
|
||||
// as this will throw... Not expected behaviour.
|
||||
var O = new Proxy(function() {}, {
|
||||
get: function() {
|
||||
throw "get trap";
|
||||
}
|
||||
});
|
||||
|
||||
function f() {
|
||||
new O();
|
||||
}
|
||||
|
||||
f();
|
||||
f();
|
||||
|
@ -980,7 +980,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
||||
#endif
|
||||
|
||||
bool pushedNewTarget = op == JSOP_NEW;
|
||||
|
||||
|
||||
// If this was the last inline frame, or we are bailing out to a catch or
|
||||
// finally block in this frame, then unpacking is almost done.
|
||||
if (!iter.moreFrames() || catchingException) {
|
||||
@ -1877,6 +1877,8 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
|
||||
case Bailout_NonSimdFloat32x4Input:
|
||||
case Bailout_InitialState:
|
||||
case Bailout_Debugger:
|
||||
case Bailout_UninitializedThis:
|
||||
case Bailout_BadDerivedConstructorReturn:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
|
@ -1285,6 +1285,30 @@ BaselineCompiler::emit_JSOP_NULL()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowUninitializedThisFn)(JSContext*, BaselineFrame* frame);
|
||||
static const VMFunction ThrowUninitializedThisInfo =
|
||||
FunctionInfo<ThrowUninitializedThisFn>(BaselineThrowUninitializedThis);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitCheckThis()
|
||||
{
|
||||
frame.assertSyncedStack();
|
||||
|
||||
Label thisOK;
|
||||
masm.branchTestMagic(Assembler::NotEqual, frame.addressOfThis(), &thisOK);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(ThrowUninitializedThisInfo))
|
||||
return false;
|
||||
|
||||
masm.bind(&thisOK);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_THIS()
|
||||
{
|
||||
@ -1299,6 +1323,12 @@ BaselineCompiler::emit_JSOP_THIS()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (script->isDerivedClassConstructor()) {
|
||||
frame.syncStack(0);
|
||||
if (!emitCheckThis())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep this value in R0
|
||||
frame.pushThis();
|
||||
|
||||
@ -2873,7 +2903,7 @@ BaselineCompiler::emitCall()
|
||||
{
|
||||
MOZ_ASSERT(IsCallPC(pc));
|
||||
|
||||
bool construct = JSOp(*pc) == JSOP_NEW;
|
||||
bool construct = JSOp(*pc) == JSOP_NEW || JSOp(*pc) == JSOP_SUPERCALL;
|
||||
uint32_t argc = GET_ARGC(pc);
|
||||
|
||||
frame.syncStack(0);
|
||||
@ -2900,13 +2930,13 @@ BaselineCompiler::emitSpreadCall()
|
||||
masm.move32(Imm32(1), R0.scratchReg());
|
||||
|
||||
// Call IC
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_SPREADNEW,
|
||||
bool construct = JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
|
||||
/* isSpread = */ true);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
|
||||
return false;
|
||||
|
||||
// Update FrameInfo.
|
||||
bool construct = JSOp(*pc) == JSOP_SPREADNEW;
|
||||
frame.popn(3 + construct);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
@ -2924,6 +2954,12 @@ BaselineCompiler::emit_JSOP_NEW()
|
||||
return emitCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SUPERCALL()
|
||||
{
|
||||
return emitCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_FUNCALL()
|
||||
{
|
||||
@ -2960,6 +2996,12 @@ BaselineCompiler::emit_JSOP_SPREADNEW()
|
||||
return emitSpreadCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SPREADSUPERCALL()
|
||||
{
|
||||
return emitSpreadCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SPREADEVAL()
|
||||
{
|
||||
@ -3290,6 +3332,10 @@ BaselineCompiler::emit_JSOP_DEBUGGER()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowBadDerivedReturnFn)(JSContext*, HandleValue);
|
||||
static const VMFunction ThrowBadDerivedReturnInfo =
|
||||
FunctionInfo<ThrowBadDerivedReturnFn>(jit::ThrowBadDerivedReturn);
|
||||
|
||||
typedef bool (*DebugEpilogueFn)(JSContext*, BaselineFrame*, jsbytecode*);
|
||||
static const VMFunction DebugEpilogueInfo =
|
||||
FunctionInfo<DebugEpilogueFn>(jit::DebugEpilogueOnBaselineReturn);
|
||||
@ -3297,6 +3343,29 @@ static const VMFunction DebugEpilogueInfo =
|
||||
bool
|
||||
BaselineCompiler::emitReturn()
|
||||
{
|
||||
if (script->isDerivedClassConstructor()) {
|
||||
frame.syncStack(0);
|
||||
|
||||
Label derivedDone, returnOK;
|
||||
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &derivedDone);
|
||||
masm.branchTestUndefined(Assembler::Equal, JSReturnOperand, &returnOK);
|
||||
|
||||
// This is going to smash JSReturnOperand, but we don't care, because it's
|
||||
// also going to throw unconditionally.
|
||||
prepareVMCall();
|
||||
pushArg(JSReturnOperand);
|
||||
if (!callVM(ThrowBadDerivedReturnInfo))
|
||||
return false;
|
||||
masm.assumeUnreachable("Should throw on bad derived constructor return");
|
||||
|
||||
masm.bind(&returnOK);
|
||||
|
||||
if (!emitCheckThis())
|
||||
return false;
|
||||
|
||||
masm.bind(&derivedDone);
|
||||
}
|
||||
|
||||
if (compileDebugInstrumentation_) {
|
||||
// Move return value into the frame's rval slot.
|
||||
masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());
|
||||
|
@ -201,7 +201,9 @@ namespace jit {
|
||||
_(JSOP_SETRVAL) \
|
||||
_(JSOP_RETRVAL) \
|
||||
_(JSOP_RETURN) \
|
||||
_(JSOP_NEWTARGET)
|
||||
_(JSOP_NEWTARGET) \
|
||||
_(JSOP_SUPERCALL) \
|
||||
_(JSOP_SPREADSUPERCALL)
|
||||
|
||||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
@ -305,6 +307,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
||||
bool emitFormalArgAccess(uint32_t arg, bool get);
|
||||
|
||||
bool emitUninitializedLexicalCheck(const ValueOperand& val);
|
||||
bool emitCheckThis();
|
||||
|
||||
bool addPCMappingEntry(bool addIndexEntry);
|
||||
|
||||
|
@ -395,6 +395,8 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, JSScript* script,
|
||||
}
|
||||
|
||||
if (val.isPrimitive()) {
|
||||
if (val.isMagic(JS_UNINITIALIZED_LEXICAL))
|
||||
return true;
|
||||
MOZ_ASSERT(!val.isMagic());
|
||||
JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
|
||||
|
||||
@ -503,10 +505,15 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
|
||||
{
|
||||
// It's possible that we arrived here from bailing out of Ion, and that
|
||||
// Ion proved that the value is dead and optimized out. In such cases, do
|
||||
// nothing.
|
||||
if (value.isMagic(JS_OPTIMIZED_OUT)) {
|
||||
res.set(value);
|
||||
return true;
|
||||
// nothing. However, it's also possible that we have an uninitialized this,
|
||||
// in which case we should not look for other magic values.
|
||||
if (stub->monitorsThis()) {
|
||||
MOZ_ASSERT_IF(value.isMagic(), value.isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
} else {
|
||||
if (value.isMagic(JS_OPTIMIZED_OUT)) {
|
||||
res.set(value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
@ -516,7 +523,10 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
|
||||
uint32_t argument;
|
||||
if (stub->monitorsThis()) {
|
||||
MOZ_ASSERT(pc == script->code());
|
||||
TypeScript::SetThis(cx, script, value);
|
||||
if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
|
||||
TypeScript::SetThis(cx, script, TypeSet::UnknownType());
|
||||
else
|
||||
TypeScript::SetThis(cx, script, value);
|
||||
} else if (stub->monitorsArgument(&argument)) {
|
||||
MOZ_ASSERT(pc == script->code());
|
||||
TypeScript::SetArgument(cx, script, argument, value);
|
||||
@ -5015,6 +5025,18 @@ TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode*
|
||||
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
|
||||
|
||||
// The CallNativeGlobal stub needs to generate 3 shape checks:
|
||||
//
|
||||
// 1. The global lexical scope shape check.
|
||||
// 2. The global object shape check.
|
||||
// 3. The holder shape check.
|
||||
//
|
||||
// 1 is done as the receiver check, as for GETNAME the global lexical scope is in the
|
||||
// receiver position. 2 is done as a manual check that other GetProp stubs don't do. 3 is
|
||||
// done as the holder check per normal.
|
||||
//
|
||||
// In the case the holder is the global object, check 2 is redundant but is not yet
|
||||
// optimized away.
|
||||
JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName/NativeGetter) stub");
|
||||
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativeGlobal, current,
|
||||
globalLexical, getter))
|
||||
@ -8622,6 +8644,8 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
JSOp op, uint32_t argc, Value* vp, bool constructing, bool isSpread,
|
||||
bool createSingleton, bool* handled)
|
||||
{
|
||||
bool isSuper = op == JSOP_SUPERCALL || op == JSOP_SPREADSUPERCALL;
|
||||
|
||||
if (createSingleton || op == JSOP_EVAL || op == JSOP_STRICTEVAL)
|
||||
return true;
|
||||
|
||||
@ -8729,9 +8753,11 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
|
||||
|
||||
// Remember the template object associated with any script being called
|
||||
// as a constructor, for later use during Ion compilation.
|
||||
// as a constructor, for later use during Ion compilation. This is unsound
|
||||
// for super(), as a single callsite can have multiple possible prototype object
|
||||
// created (via different newTargets)
|
||||
RootedObject templateObject(cx);
|
||||
if (constructing) {
|
||||
if (constructing && !isSuper) {
|
||||
// If we are calling a constructor for which the new script
|
||||
// properties analysis has not been performed yet, don't attach a
|
||||
// stub. After the analysis is performed, CreateThisForFunction may
|
||||
@ -8740,15 +8766,16 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
|
||||
// Only attach a stub if the function already has a prototype and
|
||||
// we can look it up without causing side effects.
|
||||
RootedObject newTarget(cx, &vp[2 + argc].toObject());
|
||||
RootedValue protov(cx);
|
||||
if (!GetPropertyPure(cx, fun, NameToId(cx->names().prototype), protov.address())) {
|
||||
if (!GetPropertyPure(cx, newTarget, NameToId(cx->names().prototype), protov.address())) {
|
||||
JitSpew(JitSpew_BaselineIC, " Can't purely lookup function prototype");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (protov.isObject()) {
|
||||
TaggedProto proto(&protov.toObject());
|
||||
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, nullptr, proto, fun);
|
||||
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, nullptr, proto, newTarget);
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
@ -8762,7 +8789,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
}
|
||||
}
|
||||
|
||||
JSObject* thisObject = CreateThisForFunction(cx, fun, TenuredObject);
|
||||
JSObject* thisObject = CreateThisForFunction(cx, fun, newTarget, TenuredObject);
|
||||
if (!thisObject)
|
||||
return false;
|
||||
|
||||
@ -8830,7 +8857,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
}
|
||||
|
||||
RootedObject templateObject(cx);
|
||||
if (MOZ_LIKELY(!isSpread)) {
|
||||
if (MOZ_LIKELY(!isSpread && !isSuper)) {
|
||||
bool skipAttach = false;
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach))
|
||||
@ -9516,7 +9543,8 @@ ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<Jit
|
||||
isConstructing_);
|
||||
}
|
||||
|
||||
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, MutableHandleValue rval);
|
||||
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget,
|
||||
MutableHandleValue rval);
|
||||
static const VMFunction CreateThisInfoBaseline = FunctionInfo<CreateThisFn>(CreateThis);
|
||||
|
||||
bool
|
||||
@ -9610,24 +9638,31 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
|
||||
|
||||
// Stack now looks like:
|
||||
// [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader, ArgC ]
|
||||
masm.loadValue(Address(masm.getStackPointer(), STUB_FRAME_SIZE + sizeof(size_t)), R1);
|
||||
masm.push(masm.extractObject(R1, ExtractTemp0));
|
||||
|
||||
if (isSpread_) {
|
||||
masm.loadValue(Address(masm.getStackPointer(),
|
||||
3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1);
|
||||
3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t) +
|
||||
sizeof(JSObject*)),
|
||||
R1);
|
||||
} else {
|
||||
BaseValueIndex calleeSlot2(masm.getStackPointer(), argcReg,
|
||||
2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t));
|
||||
2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t) +
|
||||
sizeof(JSObject*));
|
||||
masm.loadValue(calleeSlot2, R1);
|
||||
}
|
||||
masm.push(masm.extractObject(R1, ExtractTemp0));
|
||||
if (!callVM(CreateThisInfoBaseline, masm))
|
||||
return false;
|
||||
|
||||
// Return of CreateThis must be an object.
|
||||
// Return of CreateThis must be an object or uninitialized.
|
||||
#ifdef DEBUG
|
||||
Label createdThisIsObject;
|
||||
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisIsObject);
|
||||
masm.assumeUnreachable("The return of CreateThis must be an object.");
|
||||
masm.bind(&createdThisIsObject);
|
||||
Label createdThisOK;
|
||||
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisOK);
|
||||
masm.branchTestMagic(Assembler::Equal, JSReturnOperand, &createdThisOK);
|
||||
masm.assumeUnreachable("The return of CreateThis must be an object or uninitialized.");
|
||||
masm.bind(&createdThisOK);
|
||||
#endif
|
||||
|
||||
// Reset the register set from here on in.
|
||||
|
@ -111,7 +111,8 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
|
||||
EnterJitCode enter = cx->runtime()->jitRuntime()->enterBaseline();
|
||||
|
||||
// Caller must construct |this| before invoking the Ion function.
|
||||
MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
|
||||
MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject() ||
|
||||
data.maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
|
||||
data.result.setInt32(data.numActualArgs);
|
||||
{
|
||||
@ -131,9 +132,12 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
|
||||
|
||||
MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
|
||||
|
||||
// Jit callers wrap primitive constructor return.
|
||||
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive())
|
||||
// Jit callers wrap primitive constructor return, except for derived
|
||||
// class constructors, which are forced to do it themselves.
|
||||
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) {
|
||||
MOZ_ASSERT(data.maxArgv[0].isObject());
|
||||
data.result = data.maxArgv[0];
|
||||
}
|
||||
|
||||
// Release temporary buffer used for OSR into Ion.
|
||||
cx->runtime()->getJitRuntime(cx)->freeOsrTempData();
|
||||
@ -211,7 +215,7 @@ jit::EnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc)
|
||||
return JitExec_Aborted;
|
||||
|
||||
vals.infallibleAppend(thisv);
|
||||
|
||||
|
||||
if (fp->isFunctionFrame())
|
||||
vals.infallibleAppend(fp->newTarget());
|
||||
else
|
||||
@ -306,15 +310,6 @@ CanEnterBaselineJIT(JSContext* cx, HandleScript script, InterpreterFrame* osrFra
|
||||
MethodStatus
|
||||
jit::CanEnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, bool newType)
|
||||
{
|
||||
// If constructing, allocate a new |this| object.
|
||||
if (fp->isConstructing() && fp->functionThis().isPrimitive()) {
|
||||
RootedObject callee(cx, &fp->callee());
|
||||
RootedObject obj(cx, CreateThisForFunction(cx, callee, newType ? SingletonObject : GenericObject));
|
||||
if (!obj)
|
||||
return Method_Skipped;
|
||||
fp->functionThis().setObject(*obj);
|
||||
}
|
||||
|
||||
if (!CheckFrame(fp))
|
||||
return Method_CantCompile;
|
||||
|
||||
@ -356,8 +351,13 @@ jit::CanEnterBaselineMethod(JSContext* cx, RunState& state)
|
||||
return Method_CantCompile;
|
||||
}
|
||||
|
||||
if (!state.maybeCreateThisForConstructor(cx))
|
||||
return Method_Skipped;
|
||||
if (!state.maybeCreateThisForConstructor(cx)) {
|
||||
if (cx->isThrowingOutOfMemory()) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
return Method_Skipped;
|
||||
}
|
||||
return Method_Error;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(state.isExecute());
|
||||
ExecuteType type = state.asExecute()->type();
|
||||
|
@ -4928,13 +4928,19 @@ CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir)
|
||||
callVM(InitPropGetterSetterInfo, lir);
|
||||
}
|
||||
|
||||
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, MutableHandleValue rval);
|
||||
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
|
||||
static const VMFunction CreateThisInfoCodeGen = FunctionInfo<CreateThisFn>(CreateThis);
|
||||
|
||||
void
|
||||
CodeGenerator::visitCreateThis(LCreateThis* lir)
|
||||
{
|
||||
const LAllocation* callee = lir->getCallee();
|
||||
const LAllocation* newTarget = lir->getNewTarget();
|
||||
|
||||
if (newTarget->isConstant())
|
||||
pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(newTarget));
|
||||
|
||||
if (callee->isConstant())
|
||||
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
|
||||
@ -4945,12 +4951,14 @@ CodeGenerator::visitCreateThis(LCreateThis* lir)
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
CreateThisForFunctionWithProtoWrapper(JSContext* cx, js::HandleObject callee, HandleObject proto)
|
||||
CreateThisForFunctionWithProtoWrapper(JSContext* cx, HandleObject callee, HandleObject newTarget,
|
||||
HandleObject proto)
|
||||
{
|
||||
return CreateThisForFunctionWithProto(cx, callee, proto);
|
||||
return CreateThisForFunctionWithProto(cx, callee, newTarget, proto);
|
||||
}
|
||||
|
||||
typedef JSObject* (*CreateThisWithProtoFn)(JSContext* cx, HandleObject callee, HandleObject proto);
|
||||
typedef JSObject* (*CreateThisWithProtoFn)(JSContext* cx, HandleObject callee,
|
||||
HandleObject newTarget, HandleObject proto);
|
||||
static const VMFunction CreateThisWithProtoInfo =
|
||||
FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper);
|
||||
|
||||
@ -4958,6 +4966,7 @@ void
|
||||
CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
|
||||
{
|
||||
const LAllocation* callee = lir->getCallee();
|
||||
const LAllocation* newTarget = lir->getNewTarget();
|
||||
const LAllocation* proto = lir->getPrototype();
|
||||
|
||||
if (proto->isConstant())
|
||||
@ -4965,6 +4974,11 @@ CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
|
||||
else
|
||||
pushArg(ToRegister(proto));
|
||||
|
||||
if (newTarget->isConstant())
|
||||
pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(newTarget));
|
||||
|
||||
if (callee->isConstant())
|
||||
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
|
||||
else
|
||||
@ -10325,6 +10339,19 @@ CodeGenerator::visitNewTarget(LNewTarget *ins)
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitCheckReturn(LCheckReturn* ins)
|
||||
{
|
||||
ValueOperand returnValue = ToValue(ins, LCheckReturn::ReturnValue);
|
||||
ValueOperand thisValue = ToValue(ins, LCheckReturn::ThisValue);
|
||||
Label bail, noChecks;
|
||||
masm.branchTestObject(Assembler::Equal, returnValue, &noChecks);
|
||||
masm.branchTestUndefined(Assembler::NotEqual, returnValue, &bail);
|
||||
masm.branchTestMagicValue(Assembler::Equal, thisValue, JS_UNINITIALIZED_LEXICAL, &bail);
|
||||
bailoutFrom(&bail, ins->snapshot());
|
||||
masm.bind(&noChecks);
|
||||
}
|
||||
|
||||
// Out-of-line math_random_no_outparam call for LRandom.
|
||||
class OutOfLineRandom : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
|
@ -335,6 +335,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitDebugger(LDebugger* ins);
|
||||
void visitNewTarget(LNewTarget* ins);
|
||||
void visitArrowNewTarget(LArrowNewTarget* ins);
|
||||
void visitCheckReturn(LCheckReturn* ins);
|
||||
|
||||
void visitCheckOverRecursed(LCheckOverRecursed* lir);
|
||||
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
|
||||
|
@ -2547,8 +2547,11 @@ jit::CanEnter(JSContext* cx, RunState& state)
|
||||
}
|
||||
|
||||
if (!state.maybeCreateThisForConstructor(cx)) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
return Method_Skipped;
|
||||
if (cx->isThrowingOutOfMemory()) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
return Method_Skipped;
|
||||
}
|
||||
return Method_Error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2659,7 +2662,8 @@ EnterIon(JSContext* cx, EnterJitData& data)
|
||||
EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
|
||||
|
||||
// Caller must construct |this| before invoking the Ion function.
|
||||
MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
|
||||
MOZ_ASSERT_IF(data.constructing,
|
||||
data.maxArgv[0].isObject() || data.maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
|
||||
data.result.setInt32(data.numActualArgs);
|
||||
{
|
||||
@ -2672,9 +2676,13 @@ EnterIon(JSContext* cx, EnterJitData& data)
|
||||
|
||||
MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
|
||||
|
||||
// Jit callers wrap primitive constructor return.
|
||||
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive())
|
||||
// Jit callers wrap primitive constructor return, except for derived class constructors.
|
||||
if (!data.result.isMagic() && data.constructing &&
|
||||
data.result.isPrimitive())
|
||||
{
|
||||
MOZ_ASSERT(data.maxArgv[0].isObject());
|
||||
data.result = data.maxArgv[0];
|
||||
}
|
||||
|
||||
// Release temporary buffer used for OSR into Ion.
|
||||
cx->runtime()->getJitRuntime(cx)->freeOsrTempData();
|
||||
|
@ -1867,7 +1867,8 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
|
||||
case JSOP_CALL:
|
||||
case JSOP_NEW:
|
||||
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW);
|
||||
case JSOP_SUPERCALL:
|
||||
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL);
|
||||
|
||||
case JSOP_EVAL:
|
||||
case JSOP_STRICTEVAL:
|
||||
@ -4469,6 +4470,15 @@ IonBuilder::processReturn(JSOp op)
|
||||
MOZ_CRASH("unknown return op");
|
||||
}
|
||||
|
||||
if (script()->isDerivedClassConstructor() &&
|
||||
def->type() != MIRType_Object)
|
||||
{
|
||||
MOZ_ASSERT(info().funMaybeLazy() && info().funMaybeLazy()->isClassConstructor());
|
||||
MCheckReturn* checkRet = MCheckReturn::New(alloc(), def, current->getSlot(info().thisSlot()));
|
||||
current->add(checkRet);
|
||||
def = checkRet;
|
||||
}
|
||||
|
||||
MReturn* ret = MReturn::New(alloc(), def);
|
||||
current->end(ret);
|
||||
|
||||
@ -4944,7 +4954,7 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target)
|
||||
|
||||
// Create new |this| on the caller-side for inlined constructors.
|
||||
if (callInfo.constructing()) {
|
||||
MDefinition* thisDefn = createThis(target, callInfo.fun());
|
||||
MDefinition* thisDefn = createThis(target, callInfo.fun(), callInfo.getNewTarget());
|
||||
if (!thisDefn)
|
||||
return false;
|
||||
callInfo.setThis(thisDefn);
|
||||
@ -6038,7 +6048,7 @@ IonBuilder::createCallObject(MDefinition* callee, MDefinition* scope)
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
IonBuilder::createThisScripted(MDefinition* callee)
|
||||
IonBuilder::createThisScripted(MDefinition* callee, MDefinition* newTarget)
|
||||
{
|
||||
// Get callee.prototype.
|
||||
//
|
||||
@ -6053,12 +6063,12 @@ IonBuilder::createThisScripted(MDefinition* callee)
|
||||
// and thus invalidation.
|
||||
MInstruction* getProto;
|
||||
if (!invalidatedIdempotentCache()) {
|
||||
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), callee, names().prototype,
|
||||
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), newTarget, names().prototype,
|
||||
/* monitored = */ false);
|
||||
getPropCache->setIdempotent();
|
||||
getProto = getPropCache;
|
||||
} else {
|
||||
MCallGetProperty* callGetProp = MCallGetProperty::New(alloc(), callee, names().prototype,
|
||||
MCallGetProperty* callGetProp = MCallGetProperty::New(alloc(), newTarget, names().prototype,
|
||||
/* callprop = */ false);
|
||||
callGetProp->setIdempotent();
|
||||
getProto = callGetProp;
|
||||
@ -6066,7 +6076,7 @@ IonBuilder::createThisScripted(MDefinition* callee)
|
||||
current->add(getProto);
|
||||
|
||||
// Create this from prototype
|
||||
MCreateThisWithProto* createThis = MCreateThisWithProto::New(alloc(), callee, getProto);
|
||||
MCreateThisWithProto* createThis = MCreateThisWithProto::New(alloc(), callee, newTarget, getProto);
|
||||
current->add(createThis);
|
||||
|
||||
return createThis;
|
||||
@ -6131,6 +6141,8 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
|
||||
return nullptr;
|
||||
|
||||
JSObject* templateObject = inspector->getTemplateObject(pc);
|
||||
if (!templateObject)
|
||||
return nullptr;
|
||||
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>())
|
||||
return nullptr;
|
||||
|
||||
@ -6181,14 +6193,14 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
IonBuilder::createThis(JSFunction* target, MDefinition* callee)
|
||||
IonBuilder::createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget)
|
||||
{
|
||||
// Create |this| for unknown target.
|
||||
if (!target) {
|
||||
if (MDefinition* createThis = createThisScriptedBaseline(callee))
|
||||
return createThis;
|
||||
|
||||
MCreateThis* createThis = MCreateThis::New(alloc(), callee);
|
||||
MCreateThis* createThis = MCreateThis::New(alloc(), callee, newTarget);
|
||||
current->add(createThis);
|
||||
return createThis;
|
||||
}
|
||||
@ -6203,6 +6215,11 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee)
|
||||
return magic;
|
||||
}
|
||||
|
||||
if (target->isDerivedClassConstructor()) {
|
||||
MOZ_ASSERT(target->isClassConstructor());
|
||||
return constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
|
||||
}
|
||||
|
||||
// Try baking in the prototype.
|
||||
if (MDefinition* createThis = createThisScriptedSingleton(target, callee))
|
||||
return createThis;
|
||||
@ -6210,7 +6227,7 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee)
|
||||
if (MDefinition* createThis = createThisScriptedBaseline(callee))
|
||||
return createThis;
|
||||
|
||||
return createThisScripted(callee);
|
||||
return createThisScripted(callee, newTarget);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -6600,7 +6617,7 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo)
|
||||
|
||||
// Inline the constructor on the caller-side.
|
||||
if (callInfo.constructing()) {
|
||||
MDefinition* create = createThis(target, callInfo.fun());
|
||||
MDefinition* create = createThis(target, callInfo.fun(), callInfo.getNewTarget());
|
||||
if (!create) {
|
||||
abort("Failure inlining constructor for call.");
|
||||
return nullptr;
|
||||
@ -12749,10 +12766,22 @@ IonBuilder::jsop_this()
|
||||
|
||||
if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
|
||||
// No need to wrap primitive |this| in strict mode or self-hosted code.
|
||||
current->pushSlot(info().thisSlot());
|
||||
MDefinition* thisVal = current->getSlot(info().thisSlot());
|
||||
if (script()->isDerivedClassConstructor()) {
|
||||
MOZ_ASSERT(info().funMaybeLazy()->isClassConstructor());
|
||||
MOZ_ASSERT(script()->strict());
|
||||
|
||||
MLexicalCheck* checkThis = MLexicalCheck::New(alloc(), thisVal, Bailout_UninitializedThis);
|
||||
current->add(checkThis);
|
||||
thisVal = checkThis;
|
||||
}
|
||||
|
||||
current->push(thisVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!info().funMaybeLazy()->isClassConstructor());
|
||||
|
||||
if (thisTypes && (thisTypes->getKnownMIRType() == MIRType_Object ||
|
||||
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject())))
|
||||
{
|
||||
|
@ -380,10 +380,10 @@ class IonBuilder
|
||||
|
||||
JSObject* getSingletonPrototype(JSFunction* target);
|
||||
|
||||
MDefinition* createThisScripted(MDefinition* callee);
|
||||
MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
|
||||
MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee);
|
||||
MDefinition* createThisScriptedBaseline(MDefinition* callee);
|
||||
MDefinition* createThis(JSFunction* target, MDefinition* callee);
|
||||
MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget);
|
||||
MInstruction* createDeclEnvObject(MDefinition* callee, MDefinition* scopeObj);
|
||||
MInstruction* createCallObject(MDefinition* callee, MDefinition* scopeObj);
|
||||
|
||||
|
@ -111,8 +111,13 @@ enum BailoutKind
|
||||
// We hit a |debugger;| statement.
|
||||
Bailout_Debugger,
|
||||
|
||||
// END Normal bailouts
|
||||
// |this| used uninitialized in a derived constructor
|
||||
Bailout_UninitializedThis,
|
||||
|
||||
// Derived constructors must return object or undefined
|
||||
Bailout_BadDerivedConstructorReturn,
|
||||
|
||||
// END Normal bailouts
|
||||
|
||||
// Bailouts caused by invalid assumptions based on Baseline code.
|
||||
// Causes immediate invalidation.
|
||||
@ -151,7 +156,7 @@ enum BailoutKind
|
||||
Bailout_UninitializedLexical,
|
||||
|
||||
// A bailout to baseline from Ion on exception to handle Debugger hooks.
|
||||
Bailout_IonExceptionDebugMode,
|
||||
Bailout_IonExceptionDebugMode
|
||||
};
|
||||
|
||||
inline const char*
|
||||
@ -209,6 +214,10 @@ BailoutKindString(BailoutKind kind)
|
||||
return "Bailout_InitialState";
|
||||
case Bailout_Debugger:
|
||||
return "Bailout_Debugger";
|
||||
case Bailout_UninitializedThis:
|
||||
return "Bailout_UninitializedThis";
|
||||
case Bailout_BadDerivedConstructorReturn:
|
||||
return "Bailout_BadDerivedConstructorReturn";
|
||||
|
||||
// Bailouts caused by invalid assumptions.
|
||||
case Bailout_OverflowInvalidate:
|
||||
|
@ -328,6 +328,7 @@ LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
|
||||
{
|
||||
LCreateThisWithProto* lir =
|
||||
new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
|
||||
useRegisterOrConstantAtStart(ins->getNewTarget()),
|
||||
useRegisterOrConstantAtStart(ins->getPrototype()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
@ -336,7 +337,8 @@ LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
|
||||
void
|
||||
LIRGenerator::visitCreateThis(MCreateThis* ins)
|
||||
{
|
||||
LCreateThis* lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()));
|
||||
LCreateThis* lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()),
|
||||
useRegisterOrConstantAtStart(ins->getNewTarget()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
@ -4258,7 +4260,7 @@ LIRGenerator::visitLexicalCheck(MLexicalCheck* ins)
|
||||
MOZ_ASSERT(input->type() == MIRType_Value);
|
||||
LLexicalCheck* lir = new(alloc()) LLexicalCheck();
|
||||
useBox(lir, LLexicalCheck::Input, input);
|
||||
assignSnapshot(lir, Bailout_UninitializedLexical);
|
||||
assignSnapshot(lir, ins->bailoutKind());
|
||||
add(lir, ins);
|
||||
redefine(ins, input);
|
||||
}
|
||||
@ -4293,6 +4295,22 @@ LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins)
|
||||
define(new(alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitCheckReturn(MCheckReturn* ins)
|
||||
{
|
||||
MDefinition* retVal = ins->returnValue();
|
||||
MDefinition* thisVal = ins->thisValue();
|
||||
MOZ_ASSERT(retVal->type() == MIRType_Value);
|
||||
MOZ_ASSERT(thisVal->type() == MIRType_Value);
|
||||
|
||||
LCheckReturn* lir = new(alloc()) LCheckReturn();
|
||||
useBoxAtStart(lir, LCheckReturn::ReturnValue, retVal);
|
||||
useBoxAtStart(lir, LCheckReturn::ThisValue, thisVal);
|
||||
assignSnapshot(lir, Bailout_BadDerivedConstructorReturn);
|
||||
add(lir, ins);
|
||||
redefine(ins, retVal);
|
||||
}
|
||||
|
||||
static void
|
||||
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
|
||||
{
|
||||
|
@ -306,6 +306,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitNewTarget(MNewTarget* ins);
|
||||
void visitArrowNewTarget(MArrowNewTarget* ins);
|
||||
void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
|
||||
void visitCheckReturn(MCheckReturn* ins);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
@ -4613,11 +4613,11 @@ class MCreateThisWithTemplate
|
||||
// Caller-side allocation of |this| for |new|:
|
||||
// Given a prototype operand, construct |this| for JSOP_NEW.
|
||||
class MCreateThisWithProto
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
|
||||
: public MTernaryInstruction,
|
||||
public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
|
||||
{
|
||||
MCreateThisWithProto(MDefinition* callee, MDefinition* prototype)
|
||||
: MBinaryInstruction(callee, prototype)
|
||||
MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
|
||||
: MTernaryInstruction(callee, newTarget, prototype)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
}
|
||||
@ -4625,17 +4625,20 @@ class MCreateThisWithProto
|
||||
public:
|
||||
INSTRUCTION_HEADER(CreateThisWithProto)
|
||||
static MCreateThisWithProto* New(TempAllocator& alloc, MDefinition* callee,
|
||||
MDefinition* prototype)
|
||||
MDefinition* newTarget, MDefinition* prototype)
|
||||
{
|
||||
return new(alloc) MCreateThisWithProto(callee, prototype);
|
||||
return new(alloc) MCreateThisWithProto(callee, newTarget, prototype);
|
||||
}
|
||||
|
||||
MDefinition* getCallee() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
MDefinition* getPrototype() const {
|
||||
MDefinition* getNewTarget() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
MDefinition* getPrototype() const {
|
||||
return getOperand(2);
|
||||
}
|
||||
|
||||
// Although creation of |this| modifies global state, it is safely repeatable.
|
||||
AliasSet getAliasSet() const override {
|
||||
@ -4649,25 +4652,28 @@ class MCreateThisWithProto
|
||||
// Caller-side allocation of |this| for |new|:
|
||||
// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
|
||||
class MCreateThis
|
||||
: public MUnaryInstruction,
|
||||
public ObjectPolicy<0>::Data
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
|
||||
{
|
||||
explicit MCreateThis(MDefinition* callee)
|
||||
: MUnaryInstruction(callee)
|
||||
explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
|
||||
: MBinaryInstruction(callee, newTarget)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CreateThis)
|
||||
static MCreateThis* New(TempAllocator& alloc, MDefinition* callee)
|
||||
static MCreateThis* New(TempAllocator& alloc, MDefinition* callee, MDefinition* newTarget)
|
||||
{
|
||||
return new(alloc) MCreateThis(callee);
|
||||
return new(alloc) MCreateThis(callee, newTarget);
|
||||
}
|
||||
|
||||
MDefinition* getCallee() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
MDefinition* getNewTarget() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
// Although creation of |this| modifies global state, it is safely repeatable.
|
||||
AliasSet getAliasSet() const override {
|
||||
@ -7230,8 +7236,10 @@ class MLexicalCheck
|
||||
: public MUnaryInstruction,
|
||||
public BoxPolicy<0>::Data
|
||||
{
|
||||
explicit MLexicalCheck(MDefinition* input)
|
||||
: MUnaryInstruction(input)
|
||||
BailoutKind kind_;
|
||||
explicit MLexicalCheck(MDefinition* input, BailoutKind kind)
|
||||
: MUnaryInstruction(input),
|
||||
kind_(kind)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
setResultTypeSet(input->resultTypeSet());
|
||||
@ -7242,8 +7250,9 @@ class MLexicalCheck
|
||||
public:
|
||||
INSTRUCTION_HEADER(LexicalCheck)
|
||||
|
||||
static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input) {
|
||||
return new(alloc) MLexicalCheck(input);
|
||||
static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input,
|
||||
BailoutKind kind = Bailout_UninitializedLexical) {
|
||||
return new(alloc) MLexicalCheck(input, kind);
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
@ -7254,6 +7263,10 @@ class MLexicalCheck
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
BailoutKind bailoutKind() const {
|
||||
return kind_;
|
||||
}
|
||||
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
@ -12936,6 +12949,33 @@ class MHasClass
|
||||
}
|
||||
};
|
||||
|
||||
class MCheckReturn
|
||||
: public MBinaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
{
|
||||
explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
|
||||
: MBinaryInstruction(retVal, thisVal)
|
||||
{
|
||||
setGuard();
|
||||
setResultType(MIRType_Value);
|
||||
setResultTypeSet(retVal->resultTypeSet());
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CheckReturn)
|
||||
|
||||
static MCheckReturn* New(TempAllocator& alloc, MDefinition* retVal, MDefinition* thisVal) {
|
||||
return new (alloc) MCheckReturn(retVal, thisVal);
|
||||
}
|
||||
|
||||
MDefinition* returnValue() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
MDefinition* thisValue() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Increase the warm-up counter of the provided script upon execution and test if
|
||||
// the warm-up counter surpasses the threshold. Upon hit it will recompile the
|
||||
// outermost script (i.e. not the inlined script).
|
||||
|
@ -277,7 +277,8 @@ namespace jit {
|
||||
_(GlobalNameConflictsCheck) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget)
|
||||
_(ArrowNewTarget) \
|
||||
_(CheckReturn)
|
||||
|
||||
// Forward declarations of MIR types.
|
||||
#define FORWARD_DECLARE(op) class M##op;
|
||||
|
@ -1196,6 +1196,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
||||
_(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >) \
|
||||
_(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \
|
||||
_(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >) \
|
||||
_(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >) \
|
||||
_(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>) \
|
||||
_(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \
|
||||
_(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \
|
||||
|
@ -565,7 +565,7 @@ GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rva
|
||||
}
|
||||
|
||||
bool
|
||||
CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval)
|
||||
CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval)
|
||||
{
|
||||
rval.set(MagicValue(JS_IS_CONSTRUCTING));
|
||||
|
||||
@ -575,10 +575,14 @@ CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval)
|
||||
JSScript* script = fun->getOrCreateScript(cx);
|
||||
if (!script || !script->ensureHasTypes(cx))
|
||||
return false;
|
||||
JSObject* thisObj = CreateThisForFunction(cx, callee, GenericObject);
|
||||
if (!thisObj)
|
||||
return false;
|
||||
rval.set(ObjectValue(*thisObj));
|
||||
if (script->isDerivedClassConstructor()) {
|
||||
rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));
|
||||
} else {
|
||||
JSObject* thisObj = CreateThisForFunction(cx, callee, newTarget, GenericObject);
|
||||
if (!thisObj)
|
||||
return false;
|
||||
rval.set(ObjectValue(*thisObj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1291,5 +1295,18 @@ ThrowUninitializedLexical(JSContext* cx)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowBadDerivedReturn(JSContext* cx, HandleValue v)
|
||||
{
|
||||
ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
|
||||
{
|
||||
return ThrowUninitializedThis(cx, frame);
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
@ -634,7 +634,7 @@ bool OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out);
|
||||
|
||||
bool GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rval);
|
||||
|
||||
bool CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval);
|
||||
bool CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
|
||||
|
||||
void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
|
||||
|
||||
@ -734,6 +734,8 @@ IonMarkFunction(MIRType type)
|
||||
bool ObjectIsCallable(JSObject* obj);
|
||||
|
||||
bool ThrowUninitializedLexical(JSContext* cx);
|
||||
bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
|
||||
bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "jit/arm64/vixl/Debugger-vixl.h"
|
||||
#endif
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
@ -5,10 +5,21 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/arm64/MoveEmitter-arm64.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
MemOperand
|
||||
MoveEmitterARM64::toMemOperand(const MoveOperand& operand) const
|
||||
{
|
||||
MOZ_ASSERT(operand.isMemory());
|
||||
ARMRegister base(operand.base(), 64);
|
||||
if (operand.base() == masm.getStackPointer())
|
||||
return MemOperand(base, operand.disp() + (masm.framePushed() - pushedAtStart_));
|
||||
return MemOperand(base, operand.disp());
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterARM64::emit(const MoveResolver& moves)
|
||||
{
|
||||
|
@ -35,13 +35,7 @@ class MoveEmitterARM64
|
||||
}
|
||||
|
||||
MemOperand cycleSlot();
|
||||
MemOperand toMemOperand(const MoveOperand& operand) const {
|
||||
MOZ_ASSERT(operand.isMemory());
|
||||
ARMRegister base(operand.base(), 64);
|
||||
if (operand.base() == masm.getStackPointer())
|
||||
return MemOperand(base, operand.disp() + (masm.framePushed() - pushedAtStart_));
|
||||
return MemOperand(base, operand.disp());
|
||||
}
|
||||
MemOperand toMemOperand(const MoveOperand& operand) const;
|
||||
ARMRegister toARMReg32(const MoveOperand& operand) const {
|
||||
MOZ_ASSERT(operand.isGeneralReg());
|
||||
return ARMRegister(operand.reg(), 32);
|
||||
|
@ -256,7 +256,7 @@ const Instruction* Instruction::ImmPCOffsetTarget() const {
|
||||
}
|
||||
|
||||
|
||||
inline int Instruction::ImmBranch() const {
|
||||
int Instruction::ImmBranch() const {
|
||||
switch (BranchType()) {
|
||||
case CondBranchType: return ImmCondBranch();
|
||||
case UncondBranchType: return ImmUncondBranch();
|
||||
|
@ -1300,19 +1300,23 @@ class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1>
|
||||
|
||||
// Allocate an object for |new| on the caller-side,
|
||||
// when there is no templateObject or prototype known
|
||||
class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0>
|
||||
class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 2, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CreateThis)
|
||||
|
||||
explicit LCreateThis(const LAllocation& callee)
|
||||
LCreateThis(const LAllocation& callee, const LAllocation& newTarget)
|
||||
{
|
||||
setOperand(0, callee);
|
||||
setOperand(1, newTarget);
|
||||
}
|
||||
|
||||
const LAllocation* getCallee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* getNewTarget() {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
MCreateThis* mir() const {
|
||||
return mir_->toCreateThis();
|
||||
@ -1321,23 +1325,28 @@ class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0>
|
||||
|
||||
// Allocate an object for |new| on the caller-side,
|
||||
// when the prototype is known.
|
||||
class LCreateThisWithProto : public LCallInstructionHelper<1, 2, 0>
|
||||
class LCreateThisWithProto : public LCallInstructionHelper<1, 3, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CreateThisWithProto)
|
||||
|
||||
LCreateThisWithProto(const LAllocation& callee, const LAllocation& prototype)
|
||||
LCreateThisWithProto(const LAllocation& callee, const LAllocation& newTarget,
|
||||
const LAllocation& prototype)
|
||||
{
|
||||
setOperand(0, callee);
|
||||
setOperand(1, prototype);
|
||||
setOperand(1, newTarget);
|
||||
setOperand(2, prototype);
|
||||
}
|
||||
|
||||
const LAllocation* getCallee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* getPrototype() {
|
||||
const LAllocation* getNewTarget() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LAllocation* getPrototype() {
|
||||
return getOperand(2);
|
||||
}
|
||||
|
||||
MCreateThis* mir() const {
|
||||
return mir_->toCreateThis();
|
||||
@ -7247,6 +7256,15 @@ class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
|
||||
}
|
||||
};
|
||||
|
||||
class LCheckReturn : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
|
||||
{
|
||||
public:
|
||||
static const size_t ReturnValue = 0;
|
||||
static const size_t ThisValue = BOX_PIECES;
|
||||
|
||||
LIR_HEADER(CheckReturn)
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
@ -368,6 +368,7 @@
|
||||
_(GlobalNameConflictsCheck) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget)
|
||||
_(ArrowNewTarget) \
|
||||
_(CheckReturn)
|
||||
|
||||
#endif /* jit_shared_LOpcodes_shared_h */
|
||||
|
@ -106,6 +106,8 @@ MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeo
|
||||
MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null")
|
||||
MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
|
||||
MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors")
|
||||
MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor")
|
||||
MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")
|
||||
|
||||
// JSON
|
||||
MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
|
||||
@ -212,6 +214,7 @@ MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "can't assign to {0}
|
||||
MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
|
||||
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'")
|
||||
MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods")
|
||||
MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only valid in derived class constructors")
|
||||
MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension")
|
||||
MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list")
|
||||
MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
|
||||
@ -507,6 +510,7 @@ MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an
|
||||
|
||||
// Super
|
||||
MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'")
|
||||
MSG_DEF(JSMSG_REINIT_THIS, 0, JSEXN_REFERENCEERR, "super() called twice in derived class constructor")
|
||||
|
||||
// Modules
|
||||
MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")
|
||||
|
@ -6390,6 +6390,12 @@ JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length)
|
||||
return funobj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_SetImmutablePrototype(JSContext *cx, JS::HandleObject obj, bool *succeeded)
|
||||
{
|
||||
return SetImmutablePrototype(cx, obj, succeeded);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetAsmJSCacheOps(JSRuntime* rt, const JS::AsmJSCacheOps* ops)
|
||||
{
|
||||
|
@ -2462,6 +2462,16 @@ JS_FreezeObject(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
||||
|
||||
/*
|
||||
* Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
|
||||
* to modify it will fail. If an error occurs during the attempt, return false
|
||||
* (with a pending exception set, depending upon the nature of the error). If
|
||||
* no error occurs, return true with |*succeeded| set to indicate whether the
|
||||
* attempt successfully made the [[Prototype]] immutable.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);
|
||||
|
||||
|
@ -374,6 +374,12 @@ struct JSCompartment
|
||||
js::NewObjectMetadataState objectMetadataState;
|
||||
|
||||
public:
|
||||
// Recompute the probability with which this compartment should record
|
||||
// profiling data (stack traces, allocations log, etc.) about each
|
||||
// allocation. We consult the probabilities requested by the Debugger
|
||||
// instances observing us, if any.
|
||||
void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
|
||||
|
||||
bool hasObjectPendingMetadata() const { return objectMetadataState.is<js::PendingMetadata>(); }
|
||||
|
||||
void setObjectPendingMetadata(JSContext* cx, JSObject* obj) {
|
||||
|
@ -156,6 +156,7 @@ class JSFunction : public js::NativeObject
|
||||
nonLazyScript()->funHasExtensibleScope() ||
|
||||
nonLazyScript()->funNeedsDeclEnvObject() ||
|
||||
nonLazyScript()->needsHomeObject() ||
|
||||
nonLazyScript()->isDerivedClassConstructor() ||
|
||||
isGenerator();
|
||||
}
|
||||
|
||||
@ -516,6 +517,16 @@ class JSFunction : public js::NativeObject
|
||||
u.n.jitinfo = data;
|
||||
}
|
||||
|
||||
bool isDerivedClassConstructor() {
|
||||
bool derived;
|
||||
if (isInterpretedLazy())
|
||||
derived = lazyScript()->isDerivedClassConstructor();
|
||||
else
|
||||
derived = nonLazyScript()->isDerivedClassConstructor();
|
||||
MOZ_ASSERT_IF(derived, isClassConstructor());
|
||||
return derived;
|
||||
}
|
||||
|
||||
static unsigned offsetOfNativeOrScript() {
|
||||
static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
|
||||
"native and script pointers must be in the same spot "
|
||||
|
@ -734,15 +734,11 @@ js::math_pow(JSContext* cx, unsigned argc, Value* vp)
|
||||
return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
random_generateSeed()
|
||||
void
|
||||
js::random_generateSeed(uint64_t* seedBuffer, size_t length)
|
||||
{
|
||||
union {
|
||||
uint8_t u8[8];
|
||||
uint32_t u32[2];
|
||||
uint64_t u64;
|
||||
} seed;
|
||||
seed.u64 = 0;
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/*
|
||||
@ -760,6 +756,12 @@ random_generateSeed()
|
||||
if (oldWay && !newWay)
|
||||
MOZ_CRASH();
|
||||
|
||||
union {
|
||||
uint32_t u32[2];
|
||||
uint64_t u64;
|
||||
} seed;
|
||||
seed.u64 = 0;
|
||||
|
||||
errno_t error = rand_s(&seed.u32[0]);
|
||||
|
||||
if (oldWay)
|
||||
@ -771,24 +773,44 @@ random_generateSeed()
|
||||
|
||||
error = rand_s(&seed.u32[1]);
|
||||
MOZ_ASSERT(error == 0, "rand_s() error?!");
|
||||
|
||||
seedBuffer[0] = seed.u64 ^= PRMJ_Now();
|
||||
for (size_t i = 1; i < length; i++) {
|
||||
error = rand_s(&seed.u32[0]);
|
||||
MOZ_ASSERT(error == 0, "rand_s() error?!");
|
||||
|
||||
error = rand_s(&seed.u32[1]);
|
||||
MOZ_ASSERT(error == 0, "rand_s() error?!");
|
||||
|
||||
seedBuffer[i] = seed.u64 ^ PRMJ_Now();
|
||||
}
|
||||
|
||||
#elif defined(HAVE_ARC4RANDOM)
|
||||
seed.u32[0] = arc4random();
|
||||
seed.u32[1] = arc4random();
|
||||
union {
|
||||
uint32_t u32[2];
|
||||
uint64_t u64;
|
||||
} seed;
|
||||
seed.u64 = 0;
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
seed.u32[0] = arc4random();
|
||||
seed.u32[1] = arc4random();
|
||||
seedBuffer[i] = seed.u64 ^ PRMJ_Now();
|
||||
}
|
||||
|
||||
#elif defined(XP_UNIX)
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom?!");
|
||||
if (fd >= 0) {
|
||||
ssize_t nread = read(fd, seed.u8, mozilla::ArrayLength(seed.u8));
|
||||
MOZ_ASSERT(nread == 8, "Can't read /dev/urandom?!");
|
||||
ssize_t size = length * sizeof(seedBuffer[0]);
|
||||
ssize_t nread = read(fd, (char *) seedBuffer, size);
|
||||
MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
|
||||
mozilla::unused << nread;
|
||||
close(fd);
|
||||
}
|
||||
#else
|
||||
# error "Platform needs to implement random_generateSeed()"
|
||||
#endif
|
||||
|
||||
seed.u64 ^= PRMJ_Now();
|
||||
return seed.u64;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -798,7 +820,8 @@ void
|
||||
js::random_initState(uint64_t* rngState)
|
||||
{
|
||||
/* Our PRNG only uses 48 bits, so squeeze our entropy into those bits. */
|
||||
uint64_t seed = random_generateSeed();
|
||||
uint64_t seed;
|
||||
random_generateSeed(&seed, 1);
|
||||
seed ^= (seed >> 16);
|
||||
*rngState = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
|
||||
}
|
||||
|
@ -109,6 +109,13 @@ class MathCache
|
||||
extern JSObject*
|
||||
InitMathClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
/*
|
||||
* Fill |seed[0]| through |seed[length-1]| with random bits, suitable for
|
||||
* seeding a random number generator.
|
||||
*/
|
||||
extern void
|
||||
random_generateSeed(uint64_t* seed, size_t length);
|
||||
|
||||
extern void
|
||||
random_initState(uint64_t* rngState);
|
||||
|
||||
|
@ -967,14 +967,14 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject proto,
|
||||
NewObjectKind newKind /* = GenericObject */)
|
||||
js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject newTarget,
|
||||
HandleObject proto, NewObjectKind newKind /* = GenericObject */)
|
||||
{
|
||||
RootedObject res(cx);
|
||||
|
||||
if (proto) {
|
||||
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
|
||||
&callee->as<JSFunction>()));
|
||||
newTarget));
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
@ -986,7 +986,7 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj
|
||||
// The script was analyzed successfully and may have changed
|
||||
// the new type table, so refetch the group.
|
||||
group = ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
|
||||
&callee->as<JSFunction>());
|
||||
newTarget);
|
||||
MOZ_ASSERT(group && group->newScript());
|
||||
}
|
||||
}
|
||||
@ -1007,15 +1007,16 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::CreateThisForFunction(JSContext* cx, HandleObject callee, NewObjectKind newKind)
|
||||
js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTarget,
|
||||
NewObjectKind newKind)
|
||||
{
|
||||
RootedValue protov(cx);
|
||||
if (!GetProperty(cx, callee, callee, cx->names().prototype, &protov))
|
||||
if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov))
|
||||
return nullptr;
|
||||
RootedObject proto(cx);
|
||||
if (protov.isObject())
|
||||
proto = &protov.toObject();
|
||||
JSObject* obj = CreateThisForFunctionWithProto(cx, callee, proto, newKind);
|
||||
JSObject* obj = CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind);
|
||||
|
||||
if (obj && newKind == SingletonObject) {
|
||||
RootedPlainObject nobj(cx, &obj->as<PlainObject>());
|
||||
@ -2394,7 +2395,7 @@ JSObject::reportNotExtensible(JSContext* cx, unsigned report)
|
||||
// immutable-prototype behavior is enforced; if it's false, behavior is not
|
||||
// enforced, and immutable-prototype bits stored on objects are completely
|
||||
// ignored.
|
||||
static const bool ImmutablePrototypesEnabled = true;
|
||||
static const bool ImmutablePrototypesEnabled = false;
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
JS_ImmutablePrototypesEnabled()
|
||||
@ -3340,6 +3341,7 @@ JSObject::dump()
|
||||
if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto");
|
||||
if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access");
|
||||
if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared");
|
||||
if (!obj->hasLazyPrototype() && obj->nonLazyPrototypeIsImmutable()) fprintf(stderr, " immutable_prototype");
|
||||
|
||||
if (obj->isNative()) {
|
||||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
|
@ -1162,12 +1162,13 @@ GetInitialHeap(NewObjectKind newKind, const Class* clasp)
|
||||
// Specialized call for constructing |this| with a known function callee,
|
||||
// and a known prototype.
|
||||
extern JSObject*
|
||||
CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject proto,
|
||||
NewObjectKind newKind = GenericObject);
|
||||
CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject newTarget,
|
||||
HandleObject proto, NewObjectKind newKind = GenericObject);
|
||||
|
||||
// Specialized call for constructing |this| with a known function callee.
|
||||
extern JSObject*
|
||||
CreateThisForFunction(JSContext* cx, js::HandleObject callee, NewObjectKind newKind);
|
||||
CreateThisForFunction(JSContext* cx, js::HandleObject callee, js::HandleObject newTarget,
|
||||
NewObjectKind newKind);
|
||||
|
||||
// Generic call for constructing |this|.
|
||||
extern JSObject*
|
||||
|
@ -125,6 +125,7 @@ js::StackUses(JSScript* script, jsbytecode* pc)
|
||||
case JSOP_POPN:
|
||||
return GET_UINT16(pc);
|
||||
case JSOP_NEW:
|
||||
case JSOP_SUPERCALL:
|
||||
return 2 + GET_ARGC(pc) + 1;
|
||||
default:
|
||||
/* stack: fun, this, [argc arguments] */
|
||||
|
@ -109,30 +109,53 @@ enum JSShellExitCode {
|
||||
EXITCODE_TIMEOUT = 6
|
||||
};
|
||||
|
||||
static size_t gStackChunkSize = 8192;
|
||||
static const size_t gStackChunkSize = 8192;
|
||||
|
||||
/*
|
||||
* Note: This limit should match the stack limit set by the browser in
|
||||
* js/xpconnect/src/XPCJSRuntime.cpp
|
||||
*/
|
||||
#if defined(MOZ_ASAN) || (defined(DEBUG) && !defined(XP_WIN))
|
||||
static size_t gMaxStackSize = 2 * 128 * sizeof(size_t) * 1024;
|
||||
static const size_t gMaxStackSize = 2 * 128 * sizeof(size_t) * 1024;
|
||||
#else
|
||||
static size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
|
||||
static const size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Limit the timeout to 30 minutes to prevent an overflow on platfoms
|
||||
* that represent the time internally in microseconds using 32-bit int.
|
||||
*/
|
||||
static double MAX_TIMEOUT_INTERVAL = 1800.0;
|
||||
static double gTimeoutInterval = -1.0;
|
||||
static Atomic<bool> gServiceInterrupt;
|
||||
static JS::PersistentRootedValue gInterruptFunc;
|
||||
static const double MAX_TIMEOUT_INTERVAL = 1800.0;
|
||||
|
||||
static bool gLastWarningEnabled = false;
|
||||
static JS::PersistentRootedValue gLastWarning;
|
||||
// Per-runtime shell state.
|
||||
struct ShellRuntime
|
||||
{
|
||||
ShellRuntime();
|
||||
|
||||
bool isWorker;
|
||||
double timeoutInterval;
|
||||
Atomic<bool> serviceInterrupt;
|
||||
JS::PersistentRootedValue interruptFunc;
|
||||
bool lastWarningEnabled;
|
||||
JS::PersistentRootedValue lastWarning;
|
||||
|
||||
/*
|
||||
* Watchdog thread state.
|
||||
*/
|
||||
PRLock* watchdogLock;
|
||||
PRCondVar* watchdogWakeup;
|
||||
PRThread* watchdogThread;
|
||||
bool watchdogHasTimeout;
|
||||
int64_t watchdogTimeout;
|
||||
|
||||
PRCondVar* sleepWakeup;
|
||||
|
||||
int exitCode;
|
||||
bool quitting;
|
||||
bool gotError;
|
||||
};
|
||||
|
||||
// Shell state set once at startup.
|
||||
static bool enableCodeCoverage = false;
|
||||
static bool enableDisassemblyDumps = false;
|
||||
static bool offthreadCompilation = false;
|
||||
@ -144,11 +167,22 @@ static bool enableUnboxedArrays = false;
|
||||
#ifdef JS_GC_ZEAL
|
||||
static char gZealStr[128];
|
||||
#endif
|
||||
|
||||
static bool printTiming = false;
|
||||
static const char* jsCacheDir = nullptr;
|
||||
static const char* jsCacheAsmJSPath = nullptr;
|
||||
static bool jsCachingEnabled = false;
|
||||
static FILE* gErrFile = nullptr;
|
||||
static FILE* gOutFile = nullptr;
|
||||
static bool reportWarnings = true;
|
||||
static bool compileOnly = false;
|
||||
static bool fuzzingSafe = false;
|
||||
static bool disableOOMFunctions = false;
|
||||
#ifdef DEBUG
|
||||
static bool dumpEntrainedVariables = false;
|
||||
static bool OOM_printAllocationCount = false;
|
||||
#endif
|
||||
|
||||
// Shell state this is only accessed on the main thread.
|
||||
bool jsCachingEnabled = false;
|
||||
mozilla::Atomic<bool> jsCacheOpened(false);
|
||||
|
||||
static bool
|
||||
@ -158,7 +192,7 @@ static bool
|
||||
InitWatchdog(JSRuntime* rt);
|
||||
|
||||
static void
|
||||
KillWatchdog();
|
||||
KillWatchdog(JSRuntime *rt);
|
||||
|
||||
static bool
|
||||
ScheduleWatchdog(JSRuntime* rt, double t);
|
||||
@ -166,33 +200,6 @@ ScheduleWatchdog(JSRuntime* rt, double t);
|
||||
static void
|
||||
CancelExecution(JSRuntime* rt);
|
||||
|
||||
/*
|
||||
* Watchdog thread state.
|
||||
*/
|
||||
static PRLock* gWatchdogLock = nullptr;
|
||||
static PRCondVar* gWatchdogWakeup = nullptr;
|
||||
static PRThread* gWatchdogThread = nullptr;
|
||||
static bool gWatchdogHasTimeout = false;
|
||||
static int64_t gWatchdogTimeout = 0;
|
||||
|
||||
static PRCondVar* gSleepWakeup = nullptr;
|
||||
|
||||
static int gExitCode = 0;
|
||||
static bool gQuitting = false;
|
||||
static bool gGotError = false;
|
||||
static FILE* gErrFile = nullptr;
|
||||
static FILE* gOutFile = nullptr;
|
||||
|
||||
static bool reportWarnings = true;
|
||||
static bool compileOnly = false;
|
||||
static bool fuzzingSafe = false;
|
||||
static bool disableOOMFunctions = false;
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool dumpEntrainedVariables = false;
|
||||
static bool OOM_printAllocationCount = false;
|
||||
#endif
|
||||
|
||||
static JSContext*
|
||||
NewContext(JSRuntime* rt);
|
||||
|
||||
@ -267,6 +274,36 @@ extern JS_EXPORT_API(void) add_history(char* line);
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
ShellRuntime::ShellRuntime()
|
||||
: isWorker(false),
|
||||
timeoutInterval(-1.0),
|
||||
serviceInterrupt(false),
|
||||
lastWarningEnabled(false),
|
||||
watchdogLock(nullptr),
|
||||
watchdogWakeup(nullptr),
|
||||
watchdogThread(nullptr),
|
||||
watchdogHasTimeout(false),
|
||||
watchdogTimeout(0),
|
||||
sleepWakeup(nullptr),
|
||||
exitCode(0),
|
||||
quitting(false),
|
||||
gotError(false)
|
||||
{}
|
||||
|
||||
static ShellRuntime*
|
||||
GetShellRuntime(JSRuntime *rt)
|
||||
{
|
||||
ShellRuntime* sr = static_cast<ShellRuntime*>(JS_GetRuntimePrivate(rt));
|
||||
MOZ_ASSERT(sr);
|
||||
return sr;
|
||||
}
|
||||
|
||||
static ShellRuntime*
|
||||
GetShellRuntime(JSContext* cx)
|
||||
{
|
||||
return GetShellRuntime(cx->runtime());
|
||||
}
|
||||
|
||||
static char*
|
||||
GetLine(FILE* file, const char * prompt)
|
||||
{
|
||||
@ -370,17 +407,18 @@ GetContextData(JSContext* cx)
|
||||
static bool
|
||||
ShellInterruptCallback(JSContext* cx)
|
||||
{
|
||||
if (!gServiceInterrupt)
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
if (!sr->serviceInterrupt)
|
||||
return true;
|
||||
|
||||
// Reset gServiceInterrupt. CancelExecution or InterruptIf will set it to
|
||||
// Reset serviceInterrupt. CancelExecution or InterruptIf will set it to
|
||||
// true to distinguish watchdog or user triggered interrupts.
|
||||
// Do this first to prevent other interrupts that may occur while the
|
||||
// user-supplied callback is executing from re-entering the handler.
|
||||
gServiceInterrupt = false;
|
||||
sr->serviceInterrupt = false;
|
||||
|
||||
bool result;
|
||||
RootedValue interruptFunc(cx, gInterruptFunc);
|
||||
RootedValue interruptFunc(cx, sr->interruptFunc);
|
||||
if (!interruptFunc.isNull()) {
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
JSAutoCompartment ac(cx, &interruptFunc.toObject());
|
||||
@ -398,8 +436,8 @@ ShellInterruptCallback(JSContext* cx)
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && gExitCode == 0)
|
||||
gExitCode = EXITCODE_TIMEOUT;
|
||||
if (!result && sr->exitCode == 0)
|
||||
sr->exitCode = EXITCODE_TIMEOUT;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -432,6 +470,8 @@ SkipUTF8BOM(FILE* file)
|
||||
static void
|
||||
RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
|
||||
SkipUTF8BOM(file);
|
||||
|
||||
// To support the UNIX #! shell hack, gobble the first line if it starts
|
||||
@ -456,9 +496,9 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
.setIsRunOnce(true)
|
||||
.setNoScriptRval(true);
|
||||
|
||||
gGotError = false;
|
||||
sr->gotError = false;
|
||||
(void) JS::Compile(cx, options, file, &script);
|
||||
MOZ_ASSERT_IF(!script, gGotError);
|
||||
MOZ_ASSERT_IF(!script, sr->gotError);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -467,8 +507,8 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
|
||||
#endif
|
||||
if (script && !compileOnly) {
|
||||
if (!JS_ExecuteScript(cx, script)) {
|
||||
if (!gQuitting && gExitCode != EXITCODE_TIMEOUT)
|
||||
gExitCode = EXITCODE_RUNTIME_ERROR;
|
||||
if (!sr->quitting && sr->exitCode != EXITCODE_TIMEOUT)
|
||||
sr->exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
}
|
||||
int64_t t2 = PRMJ_Now() - t1;
|
||||
if (printTiming)
|
||||
@ -514,6 +554,7 @@ EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
|
||||
static void
|
||||
ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
int lineno = 1;
|
||||
bool hitEOF = false;
|
||||
|
||||
@ -529,7 +570,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
|
||||
CharBuffer buffer(cx);
|
||||
do {
|
||||
ScheduleWatchdog(cx->runtime(), -1);
|
||||
gServiceInterrupt = false;
|
||||
sr->serviceInterrupt = false;
|
||||
errno = 0;
|
||||
|
||||
char* line = GetLine(in, startline == lineno ? "js> " : "");
|
||||
@ -546,7 +587,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
|
||||
return;
|
||||
|
||||
lineno++;
|
||||
if (!ScheduleWatchdog(cx->runtime(), gTimeoutInterval)) {
|
||||
if (!ScheduleWatchdog(cx->runtime(), sr->timeoutInterval)) {
|
||||
hitEOF = true;
|
||||
break;
|
||||
}
|
||||
@ -561,7 +602,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
|
||||
// Catch the error, report it, and keep going.
|
||||
JS_ReportPendingException(cx);
|
||||
}
|
||||
} while (!hitEOF && !gQuitting);
|
||||
} while (!hitEOF && !sr->quitting);
|
||||
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
@ -1543,6 +1584,8 @@ Help(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool
|
||||
Quit(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// Print a message to stderr in more-deterministic builds to help jsfunfuzz
|
||||
// find uncatchable-exception bugs.
|
||||
@ -1564,8 +1607,8 @@ Quit(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
gExitCode = code;
|
||||
gQuitting = true;
|
||||
sr->exitCode = code;
|
||||
sr->quitting = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2545,9 +2588,25 @@ WorkerMain(void* arg)
|
||||
js_delete(input);
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>();
|
||||
if (!sr) {
|
||||
JS_DestroyRuntime(rt);
|
||||
js_delete(input);
|
||||
return;
|
||||
}
|
||||
|
||||
sr->isWorker = true;
|
||||
JS_SetRuntimePrivate(rt, sr.get());
|
||||
JS_SetErrorReporter(rt, my_ErrorReporter);
|
||||
SetWorkerRuntimeOptions(rt);
|
||||
|
||||
if (!InitWatchdog(rt)) {
|
||||
JS_DestroyRuntime(rt);
|
||||
js_delete(input);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = NewContext(rt);
|
||||
if (!cx) {
|
||||
JS_DestroyRuntime(rt);
|
||||
@ -2653,6 +2712,7 @@ IsBefore(int64_t t1, int64_t t2)
|
||||
static bool
|
||||
Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
int64_t t_ticks;
|
||||
|
||||
@ -2673,61 +2733,63 @@ Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
|
||||
? 0
|
||||
: int64_t(PRMJ_USEC_PER_SEC * t_secs);
|
||||
}
|
||||
PR_Lock(gWatchdogLock);
|
||||
PR_Lock(sr->watchdogLock);
|
||||
int64_t to_wakeup = PRMJ_Now() + t_ticks;
|
||||
for (;;) {
|
||||
PR_WaitCondVar(gSleepWakeup, PR_MillisecondsToInterval(t_ticks / 1000));
|
||||
if (gServiceInterrupt)
|
||||
PR_WaitCondVar(sr->sleepWakeup, PR_MillisecondsToInterval(t_ticks / 1000));
|
||||
if (sr->serviceInterrupt)
|
||||
break;
|
||||
int64_t now = PRMJ_Now();
|
||||
if (!IsBefore(now, to_wakeup))
|
||||
break;
|
||||
t_ticks = to_wakeup - now;
|
||||
}
|
||||
PR_Unlock(gWatchdogLock);
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
args.rval().setUndefined();
|
||||
return !gServiceInterrupt;
|
||||
return !sr->serviceInterrupt;
|
||||
}
|
||||
|
||||
static bool
|
||||
InitWatchdog(JSRuntime* rt)
|
||||
{
|
||||
MOZ_ASSERT(!gWatchdogThread);
|
||||
gWatchdogLock = PR_NewLock();
|
||||
if (gWatchdogLock) {
|
||||
gWatchdogWakeup = PR_NewCondVar(gWatchdogLock);
|
||||
if (gWatchdogWakeup) {
|
||||
gSleepWakeup = PR_NewCondVar(gWatchdogLock);
|
||||
if (gSleepWakeup)
|
||||
ShellRuntime* sr = GetShellRuntime(rt);
|
||||
MOZ_ASSERT(!sr->watchdogThread);
|
||||
sr->watchdogLock = PR_NewLock();
|
||||
if (sr->watchdogLock) {
|
||||
sr->watchdogWakeup = PR_NewCondVar(sr->watchdogLock);
|
||||
if (sr->watchdogWakeup) {
|
||||
sr->sleepWakeup = PR_NewCondVar(sr->watchdogLock);
|
||||
if (sr->sleepWakeup)
|
||||
return true;
|
||||
PR_DestroyCondVar(gWatchdogWakeup);
|
||||
PR_DestroyCondVar(sr->watchdogWakeup);
|
||||
}
|
||||
PR_DestroyLock(gWatchdogLock);
|
||||
PR_DestroyLock(sr->watchdogLock);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
KillWatchdog()
|
||||
KillWatchdog(JSRuntime* rt)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(rt);
|
||||
PRThread* thread;
|
||||
|
||||
PR_Lock(gWatchdogLock);
|
||||
thread = gWatchdogThread;
|
||||
PR_Lock(sr->watchdogLock);
|
||||
thread = sr->watchdogThread;
|
||||
if (thread) {
|
||||
/*
|
||||
* The watchdog thread is running, tell it to terminate waking it up
|
||||
* if necessary.
|
||||
*/
|
||||
gWatchdogThread = nullptr;
|
||||
PR_NotifyCondVar(gWatchdogWakeup);
|
||||
sr->watchdogThread = nullptr;
|
||||
PR_NotifyCondVar(sr->watchdogWakeup);
|
||||
}
|
||||
PR_Unlock(gWatchdogLock);
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
if (thread)
|
||||
PR_JoinThread(thread);
|
||||
PR_DestroyCondVar(gSleepWakeup);
|
||||
PR_DestroyCondVar(gWatchdogWakeup);
|
||||
PR_DestroyLock(gWatchdogLock);
|
||||
PR_DestroyCondVar(sr->sleepWakeup);
|
||||
PR_DestroyCondVar(sr->watchdogWakeup);
|
||||
PR_DestroyLock(sr->watchdogLock);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2736,24 +2798,25 @@ WatchdogMain(void* arg)
|
||||
PR_SetCurrentThreadName("JS Watchdog");
|
||||
|
||||
JSRuntime* rt = (JSRuntime*) arg;
|
||||
ShellRuntime* sr = GetShellRuntime(rt);
|
||||
|
||||
PR_Lock(gWatchdogLock);
|
||||
while (gWatchdogThread) {
|
||||
PR_Lock(sr->watchdogLock);
|
||||
while (sr->watchdogThread) {
|
||||
int64_t now = PRMJ_Now();
|
||||
if (gWatchdogHasTimeout && !IsBefore(now, gWatchdogTimeout)) {
|
||||
if (sr->watchdogHasTimeout && !IsBefore(now, sr->watchdogTimeout)) {
|
||||
/*
|
||||
* The timeout has just expired. Request an interrupt callback
|
||||
* outside the lock.
|
||||
*/
|
||||
gWatchdogHasTimeout = false;
|
||||
PR_Unlock(gWatchdogLock);
|
||||
sr->watchdogHasTimeout = false;
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
CancelExecution(rt);
|
||||
PR_Lock(gWatchdogLock);
|
||||
PR_Lock(sr->watchdogLock);
|
||||
|
||||
/* Wake up any threads doing sleep. */
|
||||
PR_NotifyAllCondVar(gSleepWakeup);
|
||||
PR_NotifyAllCondVar(sr->sleepWakeup);
|
||||
} else {
|
||||
if (gWatchdogHasTimeout) {
|
||||
if (sr->watchdogHasTimeout) {
|
||||
/*
|
||||
* Time hasn't expired yet. Simulate an interrupt callback
|
||||
* which doesn't abort execution.
|
||||
@ -2762,58 +2825,61 @@ WatchdogMain(void* arg)
|
||||
}
|
||||
|
||||
uint64_t sleepDuration = PR_INTERVAL_NO_TIMEOUT;
|
||||
if (gWatchdogHasTimeout)
|
||||
if (sr->watchdogHasTimeout)
|
||||
sleepDuration = PR_TicksPerSecond() / 10;
|
||||
mozilla::DebugOnly<PRStatus> status =
|
||||
PR_WaitCondVar(gWatchdogWakeup, sleepDuration);
|
||||
PR_WaitCondVar(sr->watchdogWakeup, sleepDuration);
|
||||
MOZ_ASSERT(status == PR_SUCCESS);
|
||||
}
|
||||
}
|
||||
PR_Unlock(gWatchdogLock);
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
}
|
||||
|
||||
static bool
|
||||
ScheduleWatchdog(JSRuntime* rt, double t)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(rt);
|
||||
|
||||
if (t <= 0) {
|
||||
PR_Lock(gWatchdogLock);
|
||||
gWatchdogHasTimeout = false;
|
||||
PR_Unlock(gWatchdogLock);
|
||||
PR_Lock(sr->watchdogLock);
|
||||
sr->watchdogHasTimeout = false;
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t interval = int64_t(ceil(t * PRMJ_USEC_PER_SEC));
|
||||
int64_t timeout = PRMJ_Now() + interval;
|
||||
PR_Lock(gWatchdogLock);
|
||||
if (!gWatchdogThread) {
|
||||
MOZ_ASSERT(!gWatchdogHasTimeout);
|
||||
gWatchdogThread = PR_CreateThread(PR_USER_THREAD,
|
||||
PR_Lock(sr->watchdogLock);
|
||||
if (!sr->watchdogThread) {
|
||||
MOZ_ASSERT(!sr->watchdogHasTimeout);
|
||||
sr->watchdogThread = PR_CreateThread(PR_USER_THREAD,
|
||||
WatchdogMain,
|
||||
rt,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD,
|
||||
0);
|
||||
if (!gWatchdogThread) {
|
||||
PR_Unlock(gWatchdogLock);
|
||||
if (!sr->watchdogThread) {
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
return false;
|
||||
}
|
||||
} else if (!gWatchdogHasTimeout || IsBefore(timeout, gWatchdogTimeout)) {
|
||||
PR_NotifyCondVar(gWatchdogWakeup);
|
||||
} else if (!sr->watchdogHasTimeout || IsBefore(timeout, sr->watchdogTimeout)) {
|
||||
PR_NotifyCondVar(sr->watchdogWakeup);
|
||||
}
|
||||
gWatchdogHasTimeout = true;
|
||||
gWatchdogTimeout = timeout;
|
||||
PR_Unlock(gWatchdogLock);
|
||||
sr->watchdogHasTimeout = true;
|
||||
sr->watchdogTimeout = timeout;
|
||||
PR_Unlock(sr->watchdogLock);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
CancelExecution(JSRuntime* rt)
|
||||
{
|
||||
gServiceInterrupt = true;
|
||||
ShellRuntime* sr = GetShellRuntime(rt);
|
||||
sr->serviceInterrupt = true;
|
||||
JS_RequestInterruptCallback(rt);
|
||||
|
||||
if (!gInterruptFunc.isNull()) {
|
||||
if (!sr->interruptFunc.isNull()) {
|
||||
static const char msg[] = "Script runs for too long, terminating.\n";
|
||||
fputs(msg, stderr);
|
||||
}
|
||||
@ -2827,7 +2893,7 @@ SetTimeoutValue(JSContext* cx, double t)
|
||||
JS_ReportError(cx, "Excessive timeout value");
|
||||
return false;
|
||||
}
|
||||
gTimeoutInterval = t;
|
||||
GetShellRuntime(cx)->timeoutInterval = t;
|
||||
if (!ScheduleWatchdog(cx->runtime(), t)) {
|
||||
JS_ReportError(cx, "Failed to create the watchdog");
|
||||
return false;
|
||||
@ -2838,10 +2904,11 @@ SetTimeoutValue(JSContext* cx, double t)
|
||||
static bool
|
||||
Timeout(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() == 0) {
|
||||
args.rval().setNumber(gTimeoutInterval);
|
||||
args.rval().setNumber(sr->timeoutInterval);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2860,7 +2927,7 @@ Timeout(JSContext* cx, unsigned argc, Value* vp)
|
||||
JS_ReportError(cx, "Second argument must be a timeout function");
|
||||
return false;
|
||||
}
|
||||
gInterruptFunc = value;
|
||||
sr->interruptFunc = value;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
@ -2878,7 +2945,7 @@ InterruptIf(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
if (ToBoolean(args[0])) {
|
||||
gServiceInterrupt = true;
|
||||
GetShellRuntime(cx)->serviceInterrupt = true;
|
||||
JS_RequestInterruptCallback(cx->runtime());
|
||||
}
|
||||
|
||||
@ -2895,7 +2962,7 @@ InvokeInterruptCallbackWrapper(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
gServiceInterrupt = true;
|
||||
GetShellRuntime(cx)->serviceInterrupt = true;
|
||||
JS_RequestInterruptCallback(cx->runtime());
|
||||
bool interruptRv = CheckForInterrupt(cx);
|
||||
|
||||
@ -2931,7 +2998,7 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
|
||||
JS_ReportError(cx, "Argument must be a function");
|
||||
return false;
|
||||
}
|
||||
gInterruptFunc = value;
|
||||
GetShellRuntime(cx)->interruptFunc = value;
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2940,10 +3007,11 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
|
||||
static bool
|
||||
EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
gLastWarningEnabled = true;
|
||||
gLastWarning.setNull();
|
||||
sr->lastWarningEnabled = true;
|
||||
sr->lastWarning.setNull();
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2952,10 +3020,11 @@ EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
|
||||
static bool
|
||||
DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
gLastWarningEnabled = false;
|
||||
gLastWarning.setNull();
|
||||
sr->lastWarningEnabled = false;
|
||||
sr->lastWarning.setNull();
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -2964,31 +3033,33 @@ DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
|
||||
static bool
|
||||
GetLastWarning(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!gLastWarningEnabled) {
|
||||
if (!sr->lastWarningEnabled) {
|
||||
JS_ReportError(cx, "Call enableLastWarning first.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_WrapValue(cx, &gLastWarning))
|
||||
if (!JS_WrapValue(cx, &sr->lastWarning))
|
||||
return false;
|
||||
|
||||
args.rval().set(gLastWarning);
|
||||
args.rval().set(sr->lastWarning);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ClearLastWarning(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!gLastWarningEnabled) {
|
||||
if (!sr->lastWarningEnabled) {
|
||||
JS_ReportError(cx, "Call enableLastWarning first.");
|
||||
return false;
|
||||
}
|
||||
|
||||
gLastWarning.setNull();
|
||||
sr->lastWarning.setNull();
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -3893,6 +3964,11 @@ static bool
|
||||
SetCachingEnabled(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (GetShellRuntime(cx)->isWorker) {
|
||||
JS_ReportError(cx, "Caching is not supported in workers");
|
||||
return false;
|
||||
}
|
||||
|
||||
jsCachingEnabled = ToBoolean(args.get(0));
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
@ -5142,7 +5218,7 @@ CreateLastWarningObject(JSContext* cx, JSErrorReport* report)
|
||||
if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal))
|
||||
return false;
|
||||
|
||||
gLastWarning.setObject(*warningObj);
|
||||
GetShellRuntime(cx)->lastWarning.setObject(*warningObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5184,7 +5260,9 @@ PrintStackTrace(JSContext* cx, HandleValue exn)
|
||||
void
|
||||
js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
|
||||
{
|
||||
if (report && JSREPORT_IS_WARNING(report->flags) && gLastWarningEnabled) {
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
|
||||
if (report && JSREPORT_IS_WARNING(report->flags) && sr->lastWarningEnabled) {
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
if (!CreateLastWarningObject(cx, report)) {
|
||||
fputs("Unhandled error happened while creating last warning object.\n", gOutFile);
|
||||
@ -5198,7 +5276,7 @@ js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* r
|
||||
if (JS_IsExceptionPending(cx))
|
||||
(void) JS_GetPendingException(cx, &exn);
|
||||
|
||||
gGotError = PrintError(cx, gErrFile, message, report, reportWarnings);
|
||||
sr->gotError = PrintError(cx, gErrFile, message, report, reportWarnings);
|
||||
if (!exn.isUndefined()) {
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
if (!PrintStackTrace(cx, exn))
|
||||
@ -5207,11 +5285,10 @@ js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* r
|
||||
}
|
||||
|
||||
if (report->exnType != JSEXN_NONE && !JSREPORT_IS_WARNING(report->flags)) {
|
||||
if (report->errorNumber == JSMSG_OUT_OF_MEMORY) {
|
||||
gExitCode = EXITCODE_OUT_OF_MEMORY;
|
||||
} else {
|
||||
gExitCode = EXITCODE_RUNTIME_ERROR;
|
||||
}
|
||||
if (report->errorNumber == JSMSG_OUT_OF_MEMORY)
|
||||
sr->exitCode = EXITCODE_OUT_OF_MEMORY;
|
||||
else
|
||||
sr->exitCode = EXITCODE_RUNTIME_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5222,7 +5299,7 @@ my_OOMCallback(JSContext* cx, void* data)
|
||||
// memory", which may or may not be caught. Otherwise the engine will just
|
||||
// unwind and return null/false, with no exception set.
|
||||
if (!JS_IsRunning(cx))
|
||||
gGotError = true;
|
||||
GetShellRuntime(cx)->gotError = true;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -5767,6 +5844,13 @@ NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
bool succeeded;
|
||||
if (!JS_SetImmutablePrototype(cx, glob, &succeeded))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(succeeded,
|
||||
"a fresh, unexposed global object is always capable of "
|
||||
"having its [[Prototype]] be immutable");
|
||||
|
||||
#ifdef JS_HAS_CTYPES
|
||||
if (!JS_InitCTypesClass(cx, glob))
|
||||
return nullptr;
|
||||
@ -5880,6 +5964,8 @@ OptionFailure(const char* option, const char* str)
|
||||
static int
|
||||
ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
{
|
||||
ShellRuntime* sr = GetShellRuntime(cx);
|
||||
|
||||
if (op->getBoolOption('s'))
|
||||
JS::RuntimeOptionsRef(cx).toggleExtraWarnings();
|
||||
|
||||
@ -5892,7 +5978,7 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
|
||||
if (filePaths.empty() && codeChunks.empty() && !op->getStringArg("script")) {
|
||||
Process(cx, nullptr, true); /* Interactive. */
|
||||
return gExitCode;
|
||||
return sr->exitCode;
|
||||
}
|
||||
|
||||
while (!filePaths.empty() || !codeChunks.empty()) {
|
||||
@ -5901,8 +5987,8 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
if (fpArgno < ccArgno) {
|
||||
char* path = filePaths.front();
|
||||
Process(cx, path, false);
|
||||
if (gExitCode)
|
||||
return gExitCode;
|
||||
if (sr->exitCode)
|
||||
return sr->exitCode;
|
||||
filePaths.popFront();
|
||||
} else {
|
||||
const char* code = codeChunks.front();
|
||||
@ -5910,27 +5996,27 @@ ProcessArgs(JSContext* cx, OptionParser* op)
|
||||
JS::CompileOptions opts(cx);
|
||||
opts.setFileAndLine("-e", 1);
|
||||
if (!JS::Evaluate(cx, opts, code, strlen(code), &rval))
|
||||
return gExitCode ? gExitCode : EXITCODE_RUNTIME_ERROR;
|
||||
return sr->exitCode ? sr->exitCode : EXITCODE_RUNTIME_ERROR;
|
||||
codeChunks.popFront();
|
||||
if (gQuitting)
|
||||
if (sr->quitting)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gQuitting)
|
||||
return gExitCode ? gExitCode : EXIT_SUCCESS;
|
||||
if (sr->quitting)
|
||||
return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
|
||||
|
||||
/* The |script| argument is processed after all options. */
|
||||
if (const char* path = op->getStringArg("script")) {
|
||||
Process(cx, path, false);
|
||||
if (gExitCode)
|
||||
return gExitCode;
|
||||
if (sr->exitCode)
|
||||
return sr->exitCode;
|
||||
}
|
||||
|
||||
if (op->getBoolOption('i'))
|
||||
Process(cx, nullptr, true);
|
||||
|
||||
return gExitCode ? gExitCode : EXIT_SUCCESS;
|
||||
return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -6530,13 +6616,18 @@ main(int argc, char** argv, char** envp)
|
||||
if (!rt)
|
||||
return 1;
|
||||
|
||||
mozilla::UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>();
|
||||
if (!sr)
|
||||
return 1;
|
||||
|
||||
JS_SetRuntimePrivate(rt, sr.get());
|
||||
JS_SetErrorReporter(rt, my_ErrorReporter);
|
||||
JS::SetOutOfMemoryCallback(rt, my_OOMCallback, nullptr);
|
||||
if (!SetRuntimeOptions(rt, op))
|
||||
return 1;
|
||||
|
||||
gInterruptFunc.init(rt, NullValue());
|
||||
gLastWarning.init(rt, NullValue());
|
||||
sr->interruptFunc.init(rt, NullValue());
|
||||
sr->lastWarning.init(rt, NullValue());
|
||||
|
||||
JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
|
||||
|
||||
@ -6594,7 +6685,7 @@ main(int argc, char** argv, char** envp)
|
||||
|
||||
DestroyContext(cx, true);
|
||||
|
||||
KillWatchdog();
|
||||
KillWatchdog(rt);
|
||||
|
||||
MOZ_ASSERT_IF(!CanUseExtraThreads(), workerThreads.empty());
|
||||
for (size_t i = 0; i < workerThreads.length(); i++)
|
||||
|
@ -36,11 +36,11 @@ class base {
|
||||
override() { overrideCalled = "base" }
|
||||
}
|
||||
class derived extends base {
|
||||
constructor() { };
|
||||
constructor() { super(); };
|
||||
override() { overrideCalled = "derived"; }
|
||||
}
|
||||
var derivedExpr = class extends base {
|
||||
constructor() { };
|
||||
constructor() { super(); };
|
||||
override() { overrideCalled = "derived"; }
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user