This commit is contained in:
Carsten "Tomcat" Book 2015-10-09 14:41:04 +02:00
Родитель 73acc7dfae d652ecd66e
Коммит 4457b52a0c
238 изменённых файлов: 4099 добавлений и 1445 удалений

Просмотреть файл

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please # changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more. # 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({ const LightTheme = Theme({
name: "theme-light", name: "theme-light",
styles: "chrome://browser/skin/devtools/light-theme.css", styles: "chrome://devtools/skin/themes/light-theme.css",
}); });
const DarkTheme = Theme({ const DarkTheme = Theme({
name: "theme-dark", name: "theme-dark",
styles: "chrome://browser/skin/devtools/dark-theme.css", styles: "chrome://devtools/skin/themes/dark-theme.css",
}); });
exports.LightTheme = LightTheme; exports.LightTheme = LightTheme;

Просмотреть файл

@ -48,11 +48,17 @@ html[dir="rtl"] .conversation-toolbar > li {
.conversation-toolbar .btn { .conversation-toolbar .btn {
background-position: center; background-position: center;
background-size: 24px; background-size: 28px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: transparent; background-color: transparent;
height: 24px; height: 28px;
width: 24px; 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 { .conversation-toolbar-media-btn-group-box {

Просмотреть файл

@ -26,7 +26,7 @@ npm_install:
.PHONY: dist .PHONY: dist
dist: dist:
mkdir -p dist mkdir -p dist
cp -pR content dist cp -pR content/* dist
NODE_ENV="production" $(NODE_LOCAL_BIN)/webpack \ NODE_ENV="production" $(NODE_LOCAL_BIN)/webpack \
-p -v --display-errors -p -v --display-errors
sed 's#webappEntryPoint.js#js/standalone.js#' \ sed 's#webappEntryPoint.js#js/standalone.js#' \

Просмотреть файл

@ -52,11 +52,18 @@ function chromeTimeToDate(aTime)
* GUID of the folder where items will be inserted * GUID of the folder where items will be inserted
* @param items * @param items
* bookmark items to be inserted * 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) { for (let item of items) {
try { try {
if (item.type == "url") { 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({ yield PlacesUtils.bookmarks.insert({
parentGuid, url: item.url, title: item.name parentGuid, url: item.url, title: item.name
}); });
@ -65,10 +72,11 @@ function* insertBookmarkItems(parentGuid, items) {
parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: item.name parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: item.name
})).guid; })).guid;
yield insertBookmarkItems(newFolderGuid, item.children); yield insertBookmarkItems(newFolderGuid, item.children, errorAccumulator);
} }
} catch (e) { } catch (e) {
Cu.reportError(e); Cu.reportError(e);
errorAccumulator(e);
} }
} }
} }
@ -202,6 +210,8 @@ function GetBookmarksResource(aProfileFolder) {
migrate: function(aCallback) { migrate: function(aCallback) {
return Task.spawn(function* () { return Task.spawn(function* () {
let gotErrors = false;
let errorGatherer = () => gotErrors = true;
let jsonStream = yield new Promise(resolve => let jsonStream = yield new Promise(resolve =>
NetUtil.asyncFetch({ uri: NetUtil.newURI(bookmarksFile), NetUtil.asyncFetch({ uri: NetUtil.newURI(bookmarksFile),
loadUsingSystemPrincipal: true loadUsingSystemPrincipal: true
@ -230,7 +240,7 @@ function GetBookmarksResource(aProfileFolder) {
parentGuid = parentGuid =
yield MigrationUtils.createImportedBookmarksFolder("Chrome", 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 // Importing bookmark menu items
@ -242,10 +252,13 @@ function GetBookmarksResource(aProfileFolder) {
parentGuid = parentGuid =
yield MigrationUtils.createImportedBookmarksFolder("Chrome", 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), }.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 * - Creation time least significant integer
* - Record delimiter "*" * - 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. * @note All the times are in FILETIME format.
*/ */
_parseCookieBuffer(aTextBuffer) { _parseCookieBuffer(aTextBuffer) {
// Note the last record is an empty string. // Note the last record is an empty string...
let records = [r for each (r in aTextBuffer.split("*\n")) if (r)]; 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) { for (let record of records) {
let [name, value, hostpath, flags, let [name, value, hostpath, flags,
expireTimeLo, expireTimeHi] = record.split("\n"); expireTimeLo, expireTimeHi] = record;
// IE stores deleted cookies with a zero-length value, skip them. // IE stores deleted cookies with a zero-length value, skip them.
if (value.length == 0) if (value.length == 0)
continue; 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 hostLen = hostpath.indexOf("/");
let host = hostpath.substr(0, hostLen); let host = hostpath.substr(0, hostLen);
let path = hostpath.substr(hostLen); let path = hostpath.substr(hostLen);

Просмотреть файл

@ -274,7 +274,7 @@ PlacesController.prototype = {
this.newItem("bookmark"); this.newItem("bookmark");
break; break;
case "placesCmd_new:separator": case "placesCmd_new:separator":
this.newSeparator().catch(Cu.reportError); this.newSeparator().catch(Components.utils.reportError);
break; break;
case "placesCmd_show:info": case "placesCmd_show:info":
this.showBookmarkPropertiesForSelection(); this.showBookmarkPropertiesForSelection();
@ -1309,8 +1309,8 @@ PlacesController.prototype = {
// source, otherwise report an error and fallback to a copy. // source, otherwise report an error and fallback to a copy.
if (!doCopy && if (!doCopy &&
!PlacesControllerDragHelper.canMoveUnwrappedNode(item)) { !PlacesControllerDragHelper.canMoveUnwrappedNode(item)) {
Cu.reportError("Tried to move an unmovable Places node, " + Components.utils.reportError("Tried to move an unmovable " +
"reverting to a copy operation."); "Places node, reverting to a copy operation.");
doCopy = true; doCopy = true;
} }
let guid = yield PlacesUIUtils.getTransactionForData( 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, // If this is not a copy, check for safety that we can move the source,
// otherwise report an error and fallback to a copy. // otherwise report an error and fallback to a copy.
if (action != "copy" && !PlacesControllerDragHelper.canMoveUnwrappedNode(items[i])) { if (action != "copy" && !PlacesControllerDragHelper.canMoveUnwrappedNode(items[i])) {
Components.utils.reportError("Tried to move an unmovable Places node, " + Components.utils.reportError("Tried to move an unmovable Places " +
"reverting to a copy operation."); "node, reverting to a copy operation.");
action = "copy"; action = "copy";
} }
transactions.push( transactions.push(
@ -1625,8 +1625,8 @@ var PlacesControllerDragHelper = {
// If this is not a copy, check for safety that we can move the source, // If this is not a copy, check for safety that we can move the source,
// otherwise report an error and fallback to a copy. // otherwise report an error and fallback to a copy.
if (!doCopy && !PlacesControllerDragHelper.canMoveUnwrappedNode(unwrapped)) { if (!doCopy && !PlacesControllerDragHelper.canMoveUnwrappedNode(unwrapped)) {
Components.utils.reportError("Tried to move an unmovable Places node, " + Components.utils.reportError("Tried to move an unmovable Places " +
"reverting to a copy operation."); "node, reverting to a copy operation.");
doCopy = true; doCopy = true;
} }
if (PlacesUIUtils.useAsyncTransactions) { if (PlacesUIUtils.useAsyncTransactions) {

Просмотреть файл

@ -2490,7 +2490,7 @@ var SessionStoreInternal = {
global: this._globalState.getState() 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 // get open Scratchpad window states too
let scratchpads = ScratchpadManager.getSessionState(); let scratchpads = ScratchpadManager.getSessionState();
if (scratchpads && scratchpads.length) { if (scratchpads && scratchpads.length) {

Просмотреть файл

@ -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, "size": 93197192,
"digest": "6ebd8994ac76cf6694c3d9054104219836f47578223c799cb9ba9669cfdee00112e9de56aea9d1e6d9d50ee94a201970555de19794b5fbb7546f58fdf8e59a99", "digest": "6ebd8994ac76cf6694c3d9054104219836f47578223c799cb9ba9669cfdee00112e9de56aea9d1e6d9d50ee94a201970555de19794b5fbb7546f58fdf8e59a99",
"algorithm": "sha512", "algorithm": "sha512",
"filename": "clang.tar.bz2", "filename": "clang.tar.xz",
"unpack": true, "unpack": true,
} }
] ]

Просмотреть файл

@ -6,7 +6,7 @@
"size": 97314461, "size": 97314461,
"digest": "9a74670fa917f760a4767923485d5166bbd258a8023c8aeb899b8c4d22f2847be76508ac5f26d7d2193318a2bb368a71bc62888d1bfe9d81eb45329a60451aa4", "digest": "9a74670fa917f760a4767923485d5166bbd258a8023c8aeb899b8c4d22f2847be76508ac5f26d7d2193318a2bb368a71bc62888d1bfe9d81eb45329a60451aa4",
"algorithm": "sha512", "algorithm": "sha512",
"filename": "clang.tar.xz", "filename": "clang.tar.bz2",
"unpack": true "unpack": true
}, },
{ {

Просмотреть файл

@ -66,15 +66,37 @@ public class CodeGenerator {
return (includeScope ? clsName + "::" : "") + uniqueName + "_t"; return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
} }
private String getNativeParameterType(Class<?> type, AnnotationInfo info) { /**
* 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) { 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) {
final String clsName = getMatchingClassType(type);
if (clsName != null) {
return Utils.getUnqualifiedName(clsName) + "::Param"; return Utils.getUnqualifiedName(clsName) + "::Param";
} }
return Utils.getNativeParameterType(type, info); return Utils.getNativeParameterType(type, info);
} }
private String getNativeReturnType(Class<?> type, AnnotationInfo 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.getUnqualifiedName(clsName) + "::LocalRef";
} }
return Utils.getNativeReturnType(type, info); return Utils.getNativeReturnType(type, info);
@ -370,6 +392,7 @@ public class CodeGenerator {
if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) { if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) {
Object val = null; Object val = null;
try { try {
field.setAccessible(true);
val = field.get(null); val = field.get(null);
} catch (final IllegalAccessException e) { } catch (final IllegalAccessException e) {
} }

Просмотреть файл

@ -12,7 +12,7 @@
#ifdef MOZ_ANDROID_MAX_SDK_VERSION #ifdef MOZ_ANDROID_MAX_SDK_VERSION
android:maxSdkVersion="@MOZ_ANDROID_MAX_SDK_VERSION@" android:maxSdkVersion="@MOZ_ANDROID_MAX_SDK_VERSION@"
#endif #endif
android:targetSdkVersion="@ANDROID_TARGET_SDK@"/> android:targetSdkVersion="22"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <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): def build_tar_package(tar, name, base, directory):
name = os.path.realpath(name) name = os.path.realpath(name)
run_in(base, [tar, 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]) name, directory])

Просмотреть файл

@ -39,6 +39,7 @@ support-files =
[browser_inspector_delete-selected-node-03.js] [browser_inspector_delete-selected-node-03.js]
[browser_inspector_destroy-after-navigation.js] [browser_inspector_destroy-after-navigation.js]
[browser_inspector_destroy-before-ready.js] [browser_inspector_destroy-before-ready.js]
[browser_inspector_expand-collapse.js]
[browser_inspector_gcli-inspect-command.js] [browser_inspector_gcli-inspect-command.js]
skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988. skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988.
[browser_inspector_highlighter-01.js] [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); 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 * Encapsulate some common operations for highlighter's tests, to have
* the tests cleaner, without exposing directly `inspector`, `highlighter`, and * 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> <head>
<link rel="stylesheet" href="chrome://browser/skin/" type="text/css"/> <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/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://devtools/skin/themes/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/widgets.css" type="text/css"/> <link rel="stylesheet" href="chrome://devtools/skin/themes/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/memory.css" type="text/css"/>
<script type="application/javascript;version=1.8" <script type="application/javascript;version=1.8"
src="chrome://devtools/content/shared/theme-switching.js"/> 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> <title>Census Tree 01</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <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/content/devtools/widgets.css" type="text/css" />
<link href="chrome://browser/skin/devtools/light-theme.css" type="text/css" /> <link href="chrome://devtools/skin/themes/light-theme.css" type="text/css" />
<link href="chrome://browser/skin/devtools/common.css" type="text/css" /> <link href="chrome://devtools/skin/themes/common.css" type="text/css" />
<link href="chrome://browser/skin/devtools/widgets.css" type="text/css" /> <link href="chrome://devtools/skin/themes/widgets.css" type="text/css" />
<link href="chrome://browser/skin/devtools/memory.css" type="text/css" /> <link href="chrome://devtools/skin/themes/memory.css" type="text/css" />
</head> </head>
<body> <body>
<ul id="container" style="width:100%;height:300px;"></ul> <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 // Then set spectrum's color and listen to color changes to preview them
if (this.activeSwatch) { if (this.activeSwatch) {
this.currentSwatchColor = this.activeSwatch.nextSibling; this.currentSwatchColor = this.activeSwatch.nextSibling;
this._colorUnit = this._originalColor = this.currentSwatchColor.textContent;
colorUtils.classifyColor(this.currentSwatchColor.textContent);
let color = this.activeSwatch.style.backgroundColor; let color = this.activeSwatch.style.backgroundColor;
this.spectrum.then(spectrum => { this.spectrum.then(spectrum => {
spectrum.off("changed", this._onSpectrumColorChange); spectrum.off("changed", this._onSpectrumColorChange);
@ -1224,7 +1223,7 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
_toDefaultType: function(color) { _toDefaultType: function(color) {
let colorObj = new colorUtils.CssColor(color); let colorObj = new colorUtils.CssColor(color);
colorObj.colorUnit = this._colorUnit; colorObj.setAuthoredUnitFromColor(this._originalColor);
return colorObj.toString(); return colorObj.toString();
}, },

Просмотреть файл

@ -72,6 +72,7 @@ support-files =
[browser_ruleview_colorpicker-release-outside-frame.js] [browser_ruleview_colorpicker-release-outside-frame.js]
[browser_ruleview_colorpicker-revert-on-ESC.js] [browser_ruleview_colorpicker-revert-on-ESC.js]
[browser_ruleview_colorpicker-swatch-displayed.js] [browser_ruleview_colorpicker-swatch-displayed.js]
[browser_ruleview_colorUnit.js]
[browser_ruleview_completion-existing-property_01.js] [browser_ruleview_completion-existing-property_01.js]
[browser_ruleview_completion-existing-property_02.js] [browser_ruleview_completion-existing-property_02.js]
[browser_ruleview_completion-new-property_01.js] [browser_ruleview_completion-new-property_01.js]

Просмотреть файл

@ -55,16 +55,17 @@ function* basicTest() {
} }
function* overrideTest() { 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 = let view =
yield createTestContent("#testid {" + yield createTestContent("#testid {" +
" background-image: -moz-linear-gradient" +
gradientText +
" background-image: -webkit-linear-gradient" +
gradientText +
" background-image: linear-gradient" + " background-image: linear-gradient" +
gradientText + gradientText1 +
" background-image: -ms-linear-gradient" +
gradientText2 +
" background-image: linear-gradient" +
gradientText2 +
"} "); "} ");
let elementStyle = view._elementStyle; 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; 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() { get hasAlpha() {
if (!this.valid) { if (!this.valid) {
return false; return false;

Просмотреть файл

@ -25,5 +25,10 @@ function run_test() {
for (let test of CLASSIFY_TESTS) { for (let test of CLASSIFY_TESTS) {
let result = colorUtils.classifyColor(test.input); let result = colorUtils.classifyColor(test.input);
equal(result, test.output, "test 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) { 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"; let response = "Webapps:Uninstall:Return:OK";
try { try {
@ -4140,9 +4135,7 @@ this.DOMApplicationRegistry = {
response = "Webapps:Uninstall:Return:KO"; response = "Webapps:Uninstall:Return:KO";
} }
if ((aMm = aMm.get())) {
aMm.sendAsyncMessage(response, this.formatMessage(aData)); aMm.sendAsyncMessage(response, this.formatMessage(aData));
}
}), }),
uninstall: function(aManifestURL) { uninstall: function(aManifestURL) {

Просмотреть файл

@ -114,9 +114,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource, NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource,
DOMEventTargetHelper) DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadGroup) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadGroup)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHttpChannel) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHttpChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder)
@ -490,48 +488,6 @@ EventSource::OnStopRequest(nsIRequest *aRequest,
return NS_OK; 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 // EventSource::nsIChannelEventSink
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -564,56 +520,20 @@ EventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
return NS_ERROR_DOM_SECURITY_ERR; 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 // update our channel
mHttpChannel = do_QueryInterface(mNewRedirectChannel); mHttpChannel = do_QueryInterface(aNewChannel);
NS_ENSURE_STATE(mHttpChannel); NS_ENSURE_STATE(mHttpChannel);
nsresult rv = SetupHttpChannel(); rv = SetupHttpChannel();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if ((mRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) { if ((aFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) {
rv = NS_GetFinalChannelURI(mHttpChannel, getter_AddRefs(mSrc)); rv = NS_GetFinalChannelURI(mHttpChannel, getter_AddRefs(mSrc));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
mNewRedirectChannel = nullptr; aCallback->OnRedirectVerifyCallback(NS_OK);
mRedirectCallback->OnRedirectVerifyCallback(aResult);
mRedirectCallback = nullptr;
return NS_OK; return NS_OK;
} }
@ -626,27 +546,12 @@ NS_IMETHODIMP
EventSource::GetInterface(const nsIID & aIID, EventSource::GetInterface(const nsIID & aIID,
void **aResult) 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))) { if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
mChannelEventSink = do_GetInterface(mNotificationCallbacks);
*aResult = static_cast<nsIChannelEventSink*>(this); *aResult = static_cast<nsIChannelEventSink*>(this);
NS_ADDREF_THIS(); NS_ADDREF_THIS();
return NS_OK; 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)) || if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
nsresult rv = CheckInnerWindowCorrectness(); nsresult rv = CheckInnerWindowCorrectness();
@ -807,12 +712,14 @@ EventSource::InitChannelAndRequestEventSource()
rv = SetupHttpChannel(); rv = SetupHttpChannel();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
#ifdef DEBUG
{
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks; nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks)); mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
if (notificationCallbacks != this) { MOZ_ASSERT(!notificationCallbacks);
mNotificationCallbacks = notificationCallbacks;
mHttpChannel->SetNotificationCallbacks(this);
} }
#endif
mHttpChannel->SetNotificationCallbacks(this);
// Start reading from the channel // Start reading from the channel
rv = mHttpChannel->AsyncOpen2(this); rv = mHttpChannel->AsyncOpen2(this);
@ -878,11 +785,7 @@ EventSource::ResetConnection()
mLastConvertionResult = NS_OK; mLastConvertionResult = NS_OK;
mHttpChannel = nullptr; mHttpChannel = nullptr;
mNotificationCallbacks = nullptr;
mChannelEventSink = nullptr;
mStatus = PARSE_STATE_OFF; mStatus = PARSE_STATE_OFF;
mRedirectCallback = nullptr;
mNewRedirectChannel = nullptr;
mReadyState = CONNECTING; mReadyState = CONNECTING;

Просмотреть файл

@ -34,7 +34,6 @@ class ErrorResult;
namespace dom { namespace dom {
class AsyncVerifyRedirectCallbackFwr;
struct EventSourceInit; struct EventSourceInit;
class EventSource final : public DOMEventTargetHelper class EventSource final : public DOMEventTargetHelper
@ -44,8 +43,6 @@ class EventSource final : public DOMEventTargetHelper
, public nsIInterfaceRequestor , public nsIInterfaceRequestor
, public nsSupportsWeakReference , public nsSupportsWeakReference
{ {
friend class AsyncVerifyRedirectCallbackFwr;
public: public:
explicit EventSource(nsPIDOMWindow* aOwnerWindow); explicit EventSource(nsPIDOMWindow* aOwnerWindow);
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@ -232,13 +229,6 @@ protected:
nsCOMPtr<nsILoadGroup> mLoadGroup; 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<nsIHttpChannel> mHttpChannel;
nsCOMPtr<nsITimer> mTimer; nsCOMPtr<nsITimer> mTimer;
@ -249,10 +239,6 @@ protected:
nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsIPrincipal> mPrincipal;
nsString mOrigin; nsString mOrigin;
uint32_t mRedirectFlags;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mNewRedirectChannel;
// Event Source owner information: // Event Source owner information:
// - the script file name // - the script file name
// - source code line number and column number where the Event Source object // - 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 // Note: since the scope polluter proxy lives on the window's prototype
// chain, it needs a singleton type to avoid polluting type information // chain, it needs a singleton type to avoid polluting type information
// for properties on the window. // for properties on the window.
JS::Rooted<JSObject*> gsp(aCx);
js::ProxyOptions options; js::ProxyOptions options;
options.setSingleton(true); options.setSingleton(true);
options.setClass(&WindowNamedPropertiesClass.mBase); options.setClass(&WindowNamedPropertiesClass.mBase);
return js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
JS::Rooted<JSObject*> gsp(aCx);
gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
JS::NullHandleValue, aProto, JS::NullHandleValue, aProto,
options); 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 } // namespace dom

Просмотреть файл

@ -199,6 +199,49 @@ MessageEvent::InitMessageEvent(const nsAString& aType,
return NS_OK; 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 void
MessageEvent::SetPorts(MessagePortList* aPorts) MessageEvent::SetPorts(MessagePortList* aPorts)
{ {

Просмотреть файл

@ -8,9 +8,10 @@
#define mozilla_dom_MessageEvent_h_ #define mozilla_dom_MessageEvent_h_
#include "mozilla/dom/Event.h" #include "mozilla/dom/Event.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/MessagePortList.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsIDOMMessageEvent.h" #include "nsIDOMMessageEvent.h"
#include "mozilla/dom/MessagePortList.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -19,6 +20,7 @@ struct MessageEventInit;
class MessagePort; class MessagePort;
class MessagePortList; class MessagePortList;
class OwningWindowProxyOrMessagePortOrClient; class OwningWindowProxyOrMessagePortOrClient;
class WindowProxyOrMessagePort;
namespace workers { namespace workers {
@ -85,6 +87,13 @@ public:
const MessageEventInit& aEventInit, const MessageEventInit& aEventInit,
ErrorResult& aRv); 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: protected:
~MessageEvent(); ~MessageEvent();

Просмотреть файл

@ -13,6 +13,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294
</head> </head>
<body> <body>
<script type="application/javascript"> <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() { function runTest() {
var channel = new MessageChannel(); var channel = new MessageChannel();
@ -33,20 +50,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294
var test = tests.shift(); var test = tests.shift();
var e = new MessageEvent('message', test); var e = new MessageEvent('message', test);
ok(e, "MessageEvent created"); testMessageEvent(e, test);
is(e.type, 'message', 'MessageEvent.type is right');
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok'); e = new MessageEvent('message');
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok'); e.initMessageEvent('message', true, true,
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok'); 'data' in test ? test.data : undefined,
is(e.source, 'source' in test ? test.source : null, 'MessageEvent.source is ok'); 'origin' in test ? test.origin : '',
'lastEventId' in test ? test.lastEventId : '',
if (test.ports != undefined) { 'source' in test ? test.source : null,
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok'); 'ports' in test ? test.ports : null);
is(e.ports, e.ports, 'MessageEvent.ports is ok'); testMessageEvent(e, test);
} else {
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
}
} }
try { try {

Просмотреть файл

@ -7,6 +7,7 @@
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/dom/FetchDriver.h" #include "mozilla/dom/FetchDriver.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsIOutputStream.h" #include "nsIOutputStream.h"
@ -42,7 +43,7 @@ namespace dom {
NS_IMPL_ISUPPORTS(FetchDriver, NS_IMPL_ISUPPORTS(FetchDriver,
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor, nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
nsIAsyncVerifyRedirectCallback, nsIThreadRetargetableStreamListener) nsIThreadRetargetableStreamListener)
FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal, FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup) 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 // Insert ourselves into the notification callbacks chain so we can handle
// cross-origin redirects. // 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); chan->SetNotificationCallbacks(this);
// FIXME(nsm): Bug 1120715. // FIXME(nsm): Bug 1120715.
@ -915,8 +922,6 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
{ {
NS_PRECONDITION(aNewChannel, "Redirect without a channel?"); NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
nsresult rv;
// HTTP Fetch step 5, "redirect status", step 1 // HTTP Fetch step 5, "redirect status", step 1
if (NS_WARN_IF(mRequest->GetRedirectMode() == RequestRedirect::Error)) { if (NS_WARN_IF(mRequest->GetRedirectMode() == RequestRedirect::Error)) {
aOldChannel->Cancel(NS_BINDING_FAILED); 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 // to a URL with credentials in CORS mode. This is implemented in
// nsCORSListenerProxy. // nsCORSListenerProxy.
mRedirectCallback = aCallback; // On a successful redirect we perform the following substeps of HTTP Fetch,
mOldRedirectChannel = aOldChannel; // step 5, "redirect status", step 11.
mNewRedirectChannel = aNewChannel;
nsCOMPtr<nsIChannelEventSink> outer = // Step 11.5 "Append locationURL to request's url list." so that when we set the
do_GetInterface(mNotificationCallbacks); // Response's URL from the Request's URL in Main Fetch, step 15, we get the
if (outer) { // final value. Note, we still use a single URL value instead of a list.
// The callee is supposed to call OnRedirectVerifyCallback() on success, nsCOMPtr<nsIURI> newURI;
// and nobody has to call it on failure, so we can just return after this nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
// block.
rv = outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, this);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv); aOldChannel->Cancel(rv);
mRedirectCallback = nullptr;
mOldRedirectChannel = nullptr;
mNewRedirectChannel = nullptr;
}
return 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; return NS_OK;
} }
@ -1036,21 +1099,12 @@ FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
return NS_OK; return NS_OK;
} }
nsresult rv; if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
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))) {
*aResult = static_cast<nsIStreamListener*>(this); *aResult = static_cast<nsIStreamListener*>(this);
NS_ADDREF_THIS(); NS_ADDREF_THIS();
return NS_OK; return NS_OK;
} }
else if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) { if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
*aResult = static_cast<nsIRequestObserver*>(this); *aResult = static_cast<nsIRequestObserver*>(this);
NS_ADDREF_THIS(); NS_ADDREF_THIS();
return NS_OK; return NS_OK;
@ -1059,90 +1113,6 @@ FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
return QueryInterface(aIID, 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 void
FetchDriver::SetDocument(nsIDocument* aDocument) FetchDriver::SetDocument(nsIDocument* aDocument)
{ {

Просмотреть файл

@ -8,7 +8,6 @@
#define mozilla_dom_FetchDriver_h #define mozilla_dom_FetchDriver_h
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIChannelEventSink.h" #include "nsIChannelEventSink.h"
#include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestor.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
@ -58,7 +57,6 @@ private:
class FetchDriver final : public nsIStreamListener, class FetchDriver final : public nsIStreamListener,
public nsIChannelEventSink, public nsIChannelEventSink,
public nsIInterfaceRequestor, public nsIInterfaceRequestor,
public nsIAsyncVerifyRedirectCallback,
public nsIThreadRetargetableStreamListener public nsIThreadRetargetableStreamListener
{ {
public: public:
@ -67,7 +65,6 @@ public:
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal, explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
@ -84,10 +81,6 @@ private:
nsRefPtr<InternalResponse> mResponse; nsRefPtr<InternalResponse> mResponse;
nsCOMPtr<nsIOutputStream> mPipeOutputStream; nsCOMPtr<nsIOutputStream> mPipeOutputStream;
nsRefPtr<FetchDriverObserver> mObserver; nsRefPtr<FetchDriverObserver> mObserver;
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mOldRedirectChannel;
nsCOMPtr<nsIChannel> mNewRedirectChannel;
nsCOMPtr<nsIDocument> mDocument; nsCOMPtr<nsIDocument> mDocument;
uint32_t mFetchRecursionCount; uint32_t mFetchRecursionCount;
bool mCORSFlagEverSet; bool mCORSFlagEverSet;

Просмотреть файл

@ -1443,6 +1443,7 @@ TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
a11y::DocAccessibleParent* a11y::DocAccessibleParent*
TabParent::GetTopLevelDocAccessible() const TabParent::GetTopLevelDocAccessible() const
{ {
#ifdef ACCESSIBILITY
// XXX Consider managing non top level PDocAccessibles with their parent // XXX Consider managing non top level PDocAccessibles with their parent
// document accessible. // document accessible.
const nsTArray<PDocAccessibleParent*>& docs = ManagedPDocAccessibleParent(); const nsTArray<PDocAccessibleParent*>& docs = ManagedPDocAccessibleParent();
@ -1453,7 +1454,7 @@ TabParent::GetTopLevelDocAccessible() const
return doc; return doc;
} }
} }
#endif
return nullptr; return nullptr;
} }

Просмотреть файл

@ -849,6 +849,10 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
(video ? video->GetEndTime() : -1), (video ? video->GetEndTime() : -1),
(video ? video->mDiscontinuity : 0)); (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) { switch (mState) {
case DECODER_STATE_BUFFERING: { case DECODER_STATE_BUFFERING: {
// If we're buffering, this may be the sample we need to stop 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()); DecodeTaskQueue()->Dispatch(resetTask.forget());
} }
bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData) void
MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
{ {
MOZ_ASSERT(OnTaskQueue()); 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 // Update corrupt-frames statistics
if (aData->mImage && !aData->mImage->IsValid()) { if (aData->mImage && !aData->mImage->IsValid()) {
FrameStatistics& frameStats = mDecoder->GetFrameStatistics(); FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
@ -2475,10 +2474,8 @@ bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
mCorruptFrames.clear(); mCorruptFrames.clear();
gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA"; gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA";
} }
return false;
} else { } else {
mCorruptFrames.insert(0); mCorruptFrames.insert(0);
return true;
} }
} }
@ -2500,7 +2497,7 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames,
for (uint32_t i = 0; i < frames.Length(); ++i) { for (uint32_t i = 0; i < frames.Length(); ++i) {
VideoData* frame = frames[i]->As<VideoData>(); VideoData* frame = frames[i]->As<VideoData>();
bool valid = CheckFrameValidity(frame); bool valid = !frame->mImage || frame->mImage->IsValid();
frame->mSentToCompositor = true; frame->mSentToCompositor = true;
if (!valid) { if (!valid) {

Просмотреть файл

@ -463,8 +463,9 @@ protected:
// machine thread, caller must hold the decoder lock. // machine thread, caller must hold the decoder lock.
void UpdatePlaybackPositionInternal(int64_t aTime); void UpdatePlaybackPositionInternal(int64_t aTime);
// Decode monitor must be held. // Decode monitor must be held. To determine if MDSM needs to turn off HW
bool CheckFrameValidity(VideoData* aData); // acceleration.
void CheckFrameValidity(VideoData* aData);
// Sets VideoQueue images into the VideoFrameContainer. Called on the shared // Sets VideoQueue images into the VideoFrameContainer. Called on the shared
// state machine thread. Decode monitor must be held. The first aMaxFrames // state machine thread. Decode monitor must be held. The first aMaxFrames

Просмотреть файл

@ -1,5 +1,5 @@
[DEFAULT] [DEFAULT]
skip-if = e10s || buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined) skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
support-files = support-files =
mediasource.js mediasource.js
seek.webm seek.webm^headers^ seek.webm seek.webm^headers^

Просмотреть файл

@ -66,7 +66,7 @@ public:
return mPorts[aIndex]; return mPorts[aIndex];
} }
public: private:
nsCOMPtr<nsISupports> mOwner; nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<MessagePort>> mPorts; nsTArray<nsRefPtr<MessagePort>> mPorts;
}; };

Просмотреть файл

@ -44,6 +44,12 @@ interface MessageEvent : Event {
* data, origin, source, and lastEventId attributes of this appropriately. * data, origin, source, and lastEventId attributes of this appropriately.
*/ */
readonly attribute MessagePortList? ports; 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 { dictionary MessageEventInit : EventInit {

Просмотреть файл

@ -6393,25 +6393,25 @@ nsHTMLEditRules::ReturnInHeader(Selection* aSelection,
nsIDOMNode *aNode, nsIDOMNode *aNode,
int32_t aOffset) 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 // remeber where the header is
int32_t offset; int32_t offset;
nsCOMPtr<nsIDOMNode> headerParent = nsEditor::GetNodeLocation(aHeader, &offset); nsCOMPtr<nsIDOMNode> headerParent = nsEditor::GetNodeLocation(aHeader, &offset);
// get ws code to adjust any ws // get ws code to adjust any ws
nsCOMPtr<nsINode> selNode(do_QueryInterface(aNode));
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsresult res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, nsresult res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor,
address_of(selNode), address_of(node),
&aOffset); &aOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// split the header // split the header
int32_t newOffset; NS_ENSURE_STATE(node->IsContent());
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->SplitNodeDeep(aHeader, GetAsDOMNode(selNode), aOffset, &newOffset); mHTMLEditor->SplitNodeDeep(*header, *node->AsContent(), aOffset);
NS_ENSURE_SUCCESS(res, res);
// if the leftand heading is empty, put a mozbr in it // if the leftand heading is empty, put a mozbr in it
nsCOMPtr<nsIDOMNode> prevItem; nsCOMPtr<nsIDOMNode> prevItem;
@ -6598,13 +6598,14 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
nsCOMPtr<nsIDOMNode> *aSelNode, nsCOMPtr<nsIDOMNode> *aSelNode,
int32_t *aOffset) 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; nsresult res = NS_OK;
// split para // split para
int32_t newOffset;
// get ws code to adjust any ws // get ws code to adjust any ws
nsCOMPtr<nsIDOMNode> leftPara, rightPara; nsCOMPtr<nsIContent> leftPara, rightPara;
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsINode> selNode(do_QueryInterface(*aSelNode)); nsCOMPtr<nsINode> selNode(do_QueryInterface(*aSelNode));
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), aOffset); res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), aOffset);
@ -6612,9 +6613,11 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// split the paragraph // split the paragraph
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->SplitNodeDeep(aPara, *aSelNode, *aOffset, &newOffset, false, NS_ENSURE_STATE(selNode->IsContent());
address_of(leftPara), address_of(rightPara)); mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset,
NS_ENSURE_SUCCESS(res, res); 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) // get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p)
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
if (mHTMLEditor->IsVisBreak(aBRNode)) if (mHTMLEditor->IsVisBreak(aBRNode))
@ -6631,9 +6634,9 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// check both halves of para to see if we need mozBR // check both halves of para to see if we need mozBR
res = InsertMozBRIfNeeded(leftPara); res = InsertMozBRIfNeeded(GetAsDOMNode(leftPara));
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
res = InsertMozBRIfNeeded(rightPara); res = InsertMozBRIfNeeded(GetAsDOMNode(rightPara));
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// selection to beginning of right hand para; // selection to beginning of right hand para;
@ -6751,10 +6754,9 @@ nsHTMLEditRules::ReturnInListItem(Selection* aSelection,
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset); res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// now split list item // now split list item
int32_t newOffset;
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->SplitNodeDeep(aListItem, GetAsDOMNode(selNode), aOffset, &newOffset, false); NS_ENSURE_STATE(selNode->IsContent());
NS_ENSURE_SUCCESS(res, res); mHTMLEditor->SplitNodeDeep(*listItem, *selNode->AsContent(), aOffset);
// hack: until I can change the damaged doc range code back to being // hack: until I can change the damaged doc range code back to being
// extra inclusive, I have to manually detect certain list items that // extra inclusive, I have to manually detect certain list items that
// may be left empty. // may be left empty.
@ -7156,14 +7158,15 @@ nsHTMLEditRules::SplitAsNeeded(nsIAtom& aTag,
// Could not find a place to build tag! // Could not find a place to build tag!
return NS_ERROR_FAILURE; 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. // We found a place for block, but above inOutParent. We need to split.
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsresult res = mHTMLEditor->SplitNodeDeep(splitNode->AsDOMNode(), int32_t offset = mHTMLEditor->SplitNodeDeep(*splitNode->AsContent(),
inOutParent->AsDOMNode(), *inOutParent->AsContent(),
inOutOffset, &inOutOffset); inOutOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_STATE(offset != -1);
inOutParent = tagParent; inOutParent = tagParent;
inOutOffset = offset;
} }
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -1583,10 +1583,10 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode,
NS_ENSURE_TRUE(ioOffset, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(ioOffset, NS_ERROR_NULL_POINTER);
nsresult res = NS_OK; nsresult res = NS_OK;
nsCOMPtr<nsINode> parent = do_QueryInterface(*ioParent); nsCOMPtr<nsIContent> parent = do_QueryInterface(*ioParent);
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsINode> topChild = parent; nsCOMPtr<nsIContent> topChild = parent;
int32_t offsetOfInsert = *ioOffset; nsCOMPtr<nsIContent> origParent = parent;
// Search up the parent chain to find a suitable container // Search up the parent chain to find a suitable container
while (!CanContain(*parent, *node)) { 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 // 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 // someone is trying to put block content in a span. So just put it
// where we were originally asked. // where we were originally asked.
parent = topChild = do_QueryInterface(*ioParent); parent = topChild = origParent;
NS_ENSURE_STATE(parent);
break; break;
} }
topChild = parent; topChild = parent;
parent = parent->GetParentNode(); parent = parent->GetParent();
} }
if (parent != topChild) if (parent != topChild)
{ {
// we need to split some levels above the original selection parent // we need to split some levels above the original selection parent
res = SplitNodeDeep(GetAsDOMNode(topChild), *ioParent, *ioOffset, int32_t offset = SplitNodeDeep(*topChild, *origParent, *ioOffset,
&offsetOfInsert, aNoEmptyNodes); aNoEmptyNodes ? EmptyContainers::no
NS_ENSURE_SUCCESS(res, res); : EmptyContainers::yes);
NS_ENSURE_STATE(offset != -1);
*ioParent = GetAsDOMNode(parent); *ioParent = GetAsDOMNode(parent);
*ioOffset = offsetOfInsert; *ioOffset = offset;
} }
// Now we can insert the new node // Now we can insert the new node
res = InsertNode(*node, *parent, offsetOfInsert); res = InsertNode(*node, *parent, *ioOffset);
return res; return res;
} }
@ -1927,30 +1927,31 @@ nsHTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList, cons
// Find out if the selection is collapsed: // Find out if the selection is collapsed:
bool isCollapsed = selection->Collapsed(); bool isCollapsed = selection->Collapsed();
nsCOMPtr<nsINode> node; NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
int32_t offset; selection->GetRangeAt(0)->GetStartParent() &&
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset); selection->GetRangeAt(0)->GetStartParent()->IsContent(),
if (!node) res = NS_ERROR_FAILURE; NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(res, res); OwningNonNull<nsIContent> node =
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
int32_t offset = selection->GetRangeAt(0)->StartOffset();
if (isCollapsed) if (isCollapsed)
{ {
// have to find a place to put the list // have to find a place to put the list
nsCOMPtr<nsINode> parent = node; nsCOMPtr<nsIContent> parent = node;
nsCOMPtr<nsINode> topChild = node; nsCOMPtr<nsIContent> topChild = node;
nsCOMPtr<nsIAtom> listAtom = do_GetAtom(aListType); nsCOMPtr<nsIAtom> listAtom = do_GetAtom(aListType);
while (!CanContainTag(*parent, *listAtom)) { while (!CanContainTag(*parent, *listAtom)) {
topChild = parent; topChild = parent;
parent = parent->GetParentNode(); parent = parent->GetParent();
} }
if (parent != node) if (parent != node)
{ {
// we need to split up to the child of parent // we need to split up to the child of parent
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset, offset = SplitNodeDeep(*topChild, *node, offset);
&offset); NS_ENSURE_STATE(offset != -1);
NS_ENSURE_SUCCESS(res, res);
} }
// make a list // make a list
@ -2058,31 +2059,32 @@ nsHTMLEditor::InsertBasicBlock(const nsAString& aBlockType)
// Find out if the selection is collapsed: // Find out if the selection is collapsed:
bool isCollapsed = selection->Collapsed(); bool isCollapsed = selection->Collapsed();
nsCOMPtr<nsINode> node; NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
int32_t offset; selection->GetRangeAt(0)->GetStartParent() &&
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset); selection->GetRangeAt(0)->GetStartParent()->IsContent(),
if (!node) res = NS_ERROR_FAILURE; NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(res, res); OwningNonNull<nsIContent> node =
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
int32_t offset = selection->GetRangeAt(0)->StartOffset();
if (isCollapsed) if (isCollapsed)
{ {
// have to find a place to put the block // have to find a place to put the block
nsCOMPtr<nsINode> parent = node; nsCOMPtr<nsIContent> parent = node;
nsCOMPtr<nsINode> topChild = node; nsCOMPtr<nsIContent> topChild = node;
nsCOMPtr<nsIAtom> blockAtom = do_GetAtom(aBlockType); nsCOMPtr<nsIAtom> blockAtom = do_GetAtom(aBlockType);
while (!CanContainTag(*parent, *blockAtom)) { while (!CanContainTag(*parent, *blockAtom)) {
NS_ENSURE_TRUE(parent->GetParentNode(), NS_ERROR_FAILURE); NS_ENSURE_TRUE(parent->GetParent(), NS_ERROR_FAILURE);
topChild = parent; topChild = parent;
parent = parent->GetParentNode(); parent = parent->GetParent();
} }
if (parent != node) if (parent != node)
{ {
// we need to split up to the child of parent // we need to split up to the child of parent
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset, offset = SplitNodeDeep(*topChild, *node, offset);
&offset); NS_ENSURE_STATE(offset != -1);
NS_ENSURE_SUCCESS(res, res);
} }
// make a block // make a block
@ -2128,33 +2130,34 @@ nsHTMLEditor::Indent(const nsAString& aIndent)
if (!handled) if (!handled)
{ {
// Do default - insert a blockquote node if selection collapsed // Do default - insert a blockquote node if selection collapsed
nsCOMPtr<nsINode> node;
int32_t offset;
bool isCollapsed = selection->Collapsed(); bool isCollapsed = selection->Collapsed();
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset); NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
if (!node) res = NS_ERROR_FAILURE; selection->GetRangeAt(0)->GetStartParent() &&
NS_ENSURE_SUCCESS(res, res); 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 (aIndent.EqualsLiteral("indent"))
{ {
if (isCollapsed) if (isCollapsed)
{ {
// have to find a place to put the blockquote // have to find a place to put the blockquote
nsCOMPtr<nsINode> parent = node; nsCOMPtr<nsIContent> parent = node;
nsCOMPtr<nsINode> topChild = node; nsCOMPtr<nsIContent> topChild = node;
while (!CanContainTag(*parent, *nsGkAtoms::blockquote)) { while (!CanContainTag(*parent, *nsGkAtoms::blockquote)) {
NS_ENSURE_TRUE(parent->GetParentNode(), NS_ERROR_FAILURE); NS_ENSURE_TRUE(parent->GetParent(), NS_ERROR_FAILURE);
topChild = parent; topChild = parent;
parent = parent->GetParentNode(); parent = parent->GetParent();
} }
if (parent != node) if (parent != node)
{ {
// we need to split up to the child of parent // we need to split up to the child of parent
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset = SplitNodeDeep(*topChild, *node, offset);
offset, &offset); NS_ENSURE_STATE(offset != -1);
NS_ENSURE_SUCCESS(res, res);
} }
// make a blockquote // make a blockquote
@ -2166,9 +2169,9 @@ nsHTMLEditor::Indent(const nsAString& aIndent)
res = InsertText(NS_LITERAL_STRING(" ")); res = InsertText(NS_LITERAL_STRING(" "));
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// reposition selection to before the space character // reposition selection to before the space character
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset); NS_ENSURE_STATE(selection->GetRangeAt(0));
NS_ENSURE_SUCCESS(res, res); res = selection->Collapse(selection->GetRangeAt(0)->GetStartParent(),
res = selection->Collapse(node,0); 0);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
} }
} }

Просмотреть файл

@ -592,12 +592,22 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
// or the style is specified in the style attribute // or the style is specified in the style attribute
isSet) { isSet) {
// found a style node we need to split // found a style node we need to split
nsresult rv = SplitNodeDeep(GetAsDOMNode(node), *aNode, *aOffset, nsCOMPtr<nsIContent> outLeftContent, outRightContent;
&offset, false, outLeftNode, outRightNode); nsCOMPtr<nsIContent> nodeParam = do_QueryInterface(*aNode);
NS_ENSURE_SUCCESS(rv, rv); 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 // reset startNode/startOffset
*aNode = GetAsDOMNode(node->GetParent()); *aNode = GetAsDOMNode(node->GetParent());
*aOffset = offset; *aOffset = offset;
if (outLeftNode) {
*outLeftNode = GetAsDOMNode(outLeftContent);
}
if (outRightNode) {
*outRightNode = GetAsDOMNode(outRightContent);
}
} }
node = node->GetParent(); node = node->GetParent();
} }

Просмотреть файл

@ -837,20 +837,18 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
aSize.width, aSize.height, aSize.width, aSize.height,
GfxFormatToSkiaColorType(aFormat), GfxFormatToSkiaColorType(aFormat),
alphaType); 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)); SkBitmap bitmap;
if (!device) { bitmap.setInfo(skiInfo, stride);
return false;
}
SkBitmap bitmap = device->accessBitmap(true);
if (!bitmap.allocPixels()) { if (!bitmap.allocPixels()) {
return false; return false;
} }
bitmap.eraseARGB(0, 0, 0, 0); bitmap.eraseARGB(0, 0, 0, 0);
mCanvas.adopt(new SkCanvas(device.get())); mCanvas.adopt(new SkCanvas(bitmap));
mSize = aSize; mSize = aSize;
mFormat = aFormat; mFormat = aFormat;

Просмотреть файл

@ -64,6 +64,11 @@ SourceSurfaceD2DTarget::GetDataSurface()
desc.BindFlags = 0; desc.BindFlags = 0;
desc.MiscFlags = 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)); HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture));
if (FAILED(hr)) { if (FAILED(hr)) {

Просмотреть файл

@ -1352,6 +1352,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
SymLoadStruct mapBufferRangeSymbols[] = { SymLoadStruct mapBufferRangeSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } }, { (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } },
{ (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } }, { (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } },
{ (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
END_SYMBOLS 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, static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
SkPoint* strokeSize) { SkPoint* strokeSize) {
if (SkPaint::kMiter_Join != paint.getStrokeJoin() || if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
@ -812,12 +822,22 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
devRect.sort(); devRect.sort();
// look for the quick exit, before we build a blitter // look for the quick exit, before we build a blitter
SkIRect ir; SkRect bbox = devRect;
devRect.roundOut(&ir);
if (paint.getStyle() != SkPaint::kFill_Style) { if (paint.getStyle() != SkPaint::kFill_Style) {
// extra space for hairlines // 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)) { if (fRC->quickReject(ir)) {
return; return;
} }

Просмотреть файл

@ -2157,13 +2157,9 @@ gfxPlatform::PerfWarnings()
return gfxPrefs::PerfWarnings(); return gfxPrefs::PerfWarnings();
} }
void static inline bool
gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends) 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"); nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) { if (gfxInfo) {
// bug 655578: on X11 at least, we must always call GetData (even if we don't need that information) // bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
@ -2175,10 +2171,24 @@ gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends
int32_t status; int32_t status;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) { if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK) { if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
*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); aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
whitelisted = true;
}
}
} }
if (!whitelisted) { if (!whitelisted) {

Просмотреть файл

@ -1967,6 +1967,10 @@ gfxWindowsPlatform::CheckD3D11Support(bool* aCanUseHardware)
*aCanUseHardware = false; *aCanUseHardware = false;
return FeatureStatus::Available; return FeatureStatus::Available;
} }
if (gfxPrefs::LayersAccelerationForceEnabled()) {
*aCanUseHardware = true;
return FeatureStatus::Available;
}
if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) { if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
int32_t status; int32_t status;

Просмотреть файл

@ -1792,6 +1792,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
#elif defined(JS_CODEGEN_ARM64) #elif defined(JS_CODEGEN_ARM64)
MOZ_CRASH(); MOZ_CRASH();
void* callee = nullptr; void* callee = nullptr;
(void)callerRetAddr;
#elif defined(JS_CODEGEN_MIPS32) #elif defined(JS_CODEGEN_MIPS32)
Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t)); Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next()); void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
@ -1817,6 +1818,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
#elif defined(JS_CODEGEN_ARM) #elif defined(JS_CODEGEN_ARM)
new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always); new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always);
#elif defined(JS_CODEGEN_ARM64) #elif defined(JS_CODEGEN_ARM64)
(void)newCallee;
MOZ_CRASH(); MOZ_CRASH();
#elif defined(JS_CODEGEN_MIPS32) #elif defined(JS_CODEGEN_MIPS32)
Assembler::WriteLuiOriInstructions(instr, instr->next(), Assembler::WriteLuiOriInstructions(instr, instr->next(),
@ -1882,6 +1884,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
new (jump) InstNOP(); new (jump) InstNOP();
} }
#elif defined(JS_CODEGEN_ARM64) #elif defined(JS_CODEGEN_ARM64)
(void)jump;
(void)profilingEpilogue;
MOZ_CRASH(); MOZ_CRASH();
#elif defined(JS_CODEGEN_MIPS32) #elif defined(JS_CODEGEN_MIPS32)
Instruction* instr = (Instruction*)jump; Instruction* instr = (Instruction*)jump;

Просмотреть файл

@ -3111,13 +3111,20 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_NEW: case PNK_NEW:
case PNK_TAGGED_TEMPLATE: case PNK_TAGGED_TEMPLATE:
case PNK_CALL: case PNK_CALL:
case PNK_SUPERCALL:
{ {
ParseNode* next = pn->pn_head; ParseNode* next = pn->pn_head;
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
RootedValue callee(cx); RootedValue callee(cx);
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)) if (!expression(next, &callee))
return false; return false;
}
NodeVector args(cx); NodeVector args(cx);
if (!args.reserve(pn->pn_count - 1)) if (!args.reserve(pn->pn_count - 1))
@ -3135,6 +3142,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
if (pn->getKind() == PNK_TAGGED_TEMPLATE) if (pn->getKind() == PNK_TAGGED_TEMPLATE)
return builder.taggedTemplate(callee, args, &pn->pn_pos, dst); return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
// SUPERCALL is Call(super, args)
return pn->isKind(PNK_NEW) return pn->isKind(PNK_NEW)
? builder.newExpression(callee, args, &pn->pn_pos, dst) ? 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)) if (!ToInt32(cx, args[0], &seed))
return false; return false;
cx->compartment()->savedStacks().setRNGState((seed ^ RNG_MULTIPLIER) & RNG_MASK); cx->compartment()->savedStacks().setRNGState(seed, seed * 33);
return true; return true;
} }

Просмотреть файл

@ -1934,7 +1934,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_TRUE: case PNK_TRUE:
case PNK_FALSE: case PNK_FALSE:
case PNK_NULL: case PNK_NULL:
case PNK_THIS:
case PNK_ELISION: case PNK_ELISION:
case PNK_GENERATOR: case PNK_GENERATOR:
case PNK_NUMBER: case PNK_NUMBER:
@ -1943,6 +1942,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = false; *answer = false;
return true; 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. // Trivial binary nodes with more token pos holders.
case PNK_NEWTARGET: case PNK_NEWTARGET:
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_BINARY));
@ -2185,6 +2190,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_NEW: case PNK_NEW:
case PNK_CALL: case PNK_CALL:
case PNK_TAGGED_TEMPLATE: case PNK_TAGGED_TEMPLATE:
case PNK_SUPERCALL:
MOZ_ASSERT(pn->isArity(PN_LIST)); MOZ_ASSERT(pn->isArity(PN_LIST));
*answer = true; *answer = true;
return true; return true;
@ -6727,6 +6733,12 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
} }
callop = false; callop = false;
break; 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: default:
if (!emitTree(pn2)) if (!emitTree(pn2))
return false; return false;
@ -6739,7 +6751,8 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
return false; 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 * Emit code for each argument in order, then emit the JSOP_*CALL or
@ -6755,19 +6768,29 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
} }
if (isNewOp) { if (isNewOp) {
if (pn->isKind(PNK_SUPERCALL)) {
if (!emit1(JSOP_NEWTARGET))
return false;
} else {
// Repush the callee as new.target // Repush the callee as new.target
if (!emitDupAt(argc + 1)) if (!emitDupAt(argc + 1))
return false; return false;
} }
}
} else { } else {
if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY)) if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
return false; return false;
if (isNewOp) { if (isNewOp) {
if (pn->isKind(PNK_SUPERCALL)) {
if (!emit1(JSOP_NEWTARGET))
return false;
} else {
if (!emitDupAt(2)) if (!emitDupAt(2))
return false; return false;
} }
} }
}
emittingForInit = oldEmittingForInit; emittingForInit = oldEmittingForInit;
if (!spread) { if (!spread) {
@ -6791,6 +6814,9 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS)) if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
return false; return false;
} }
if (pn->isKind(PNK_SUPERCALL) && !emit1(JSOP_SETTHIS))
return false;
return true; return true;
} }
@ -7847,6 +7873,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
case PNK_TAGGED_TEMPLATE: case PNK_TAGGED_TEMPLATE:
case PNK_CALL: case PNK_CALL:
case PNK_GENEXP: case PNK_GENEXP:
case PNK_SUPERCALL:
ok = emitCallOrNew(pn); ok = emitCallOrNew(pn);
break; break;

Просмотреть файл

@ -414,6 +414,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CLASSNAMES: case PNK_CLASSNAMES:
case PNK_NEWTARGET: case PNK_NEWTARGET:
case PNK_POSHOLDER: case PNK_POSHOLDER:
case PNK_SUPERCALL:
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on " MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
"some parent node without recurring to test this node"); "some parent node without recurring to test this node");
@ -1579,7 +1580,8 @@ static bool
FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser, FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda) 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)); MOZ_ASSERT(node->isArity(PN_LIST));
// Don't fold a parenthesized callable component in an invocation, as this // 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); return FoldAdd(cx, pnp, parser, inGenexpLambda);
case PNK_CALL: case PNK_CALL:
case PNK_SUPERCALL:
case PNK_TAGGED_TEMPLATE: case PNK_TAGGED_TEMPLATE:
return FoldCall(cx, pn, parser, inGenexpLambda); return FoldCall(cx, pn, parser, inGenexpLambda);

Просмотреть файл

@ -376,6 +376,7 @@ class NameResolver
case PNK_EXPORT_BATCH_SPEC: case PNK_EXPORT_BATCH_SPEC:
case PNK_FRESHENBLOCK: case PNK_FRESHENBLOCK:
case PNK_OBJECT_PROPERTY_NAME: case PNK_OBJECT_PROPERTY_NAME:
case PNK_POSHOLDER:
MOZ_ASSERT(cur->isArity(PN_NULLARY)); MOZ_ASSERT(cur->isArity(PN_NULLARY));
break; break;
@ -673,6 +674,7 @@ class NameResolver
case PNK_COMMA: case PNK_COMMA:
case PNK_NEW: case PNK_NEW:
case PNK_CALL: case PNK_CALL:
case PNK_SUPERCALL:
case PNK_GENEXP: case PNK_GENEXP:
case PNK_ARRAY: case PNK_ARRAY:
case PNK_STATEMENTLIST: case PNK_STATEMENTLIST:
@ -796,7 +798,6 @@ class NameResolver
case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
case PNK_CLASSNAMES: // by PNK_CLASS case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_POSHOLDER: // by PNK_NEWTARGET, PNK_DOT
MOZ_CRASH("should have been handled by a parent node"); MOZ_CRASH("should have been handled by a parent node");
case PNK_LIMIT: // invalid sentinel value case PNK_LIMIT: // invalid sentinel value

Просмотреть файл

@ -489,6 +489,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_COMMA: case PNK_COMMA:
case PNK_NEW: case PNK_NEW:
case PNK_CALL: case PNK_CALL:
case PNK_SUPERCALL:
case PNK_GENEXP: case PNK_GENEXP:
case PNK_ARRAY: case PNK_ARRAY:
case PNK_OBJECT: case PNK_OBJECT:

Просмотреть файл

@ -175,6 +175,7 @@ class PackedScopeCoordinate
F(CLASSNAMES) \ F(CLASSNAMES) \
F(NEWTARGET) \ F(NEWTARGET) \
F(POSHOLDER) \ F(POSHOLDER) \
F(SUPERCALL) \
\ \
/* Unary operators. */ \ /* Unary operators. */ \
F(TYPEOFNAME) \ F(TYPEOFNAME) \

Просмотреть файл

@ -8648,11 +8648,33 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
tt == TOK_NO_SUBS_TEMPLATE) tt == TOK_NO_SUBS_TEMPLATE)
{ {
if (handler.isSuperBase(lhs, context)) { if (handler.isSuperBase(lhs, context)) {
// For now... 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); report(ParseError, false, null(), JSMSG_BAD_SUPER);
return null(); 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(); nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
if (!nextMember) if (!nextMember)
return null(); return null();

Просмотреть файл

@ -374,6 +374,7 @@ class FunctionBox : public ObjectBox, public SharedContext
hasExtensibleScope() || hasExtensibleScope() ||
needsDeclEnvObject() || needsDeclEnvObject() ||
needsHomeObject() || needsHomeObject() ||
isDerivedClassConstructor() ||
isGenerator(); isGenerator();
} }
}; };

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| error:InternalError // |jit-test| error:TypeError
// Binary: cache/js-dbg-32-4ce3983a43f4-linux // Binary: cache/js-dbg-32-4ce3983a43f4-linux
// Flags: // Flags:

Просмотреть файл

@ -1,13 +1,15 @@
// |jit-test| error: ExitCleanly // |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 = 1 },
function(){ this.x = 2 }))).x, 2); function(){ this.x = 2 }))).x, 2);
// proxies can return the callee // 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); assertEq(new x(x), x);
try { try {
var x = (Proxy.createFunction({}, "".indexOf)); var x = (Proxy.createFunction(handler, "".indexOf));
new x; new x;
throw "Should not be reached" throw "Should not be reached"
} }

Просмотреть файл

@ -32,5 +32,5 @@ dbg.memory.trackingAllocationSites = true;
// probability is fine. // probability is fine.
measure(0.0, 0); measure(0.0, 0);
measure(1.0, 100); measure(1.0, 100);
measure(0.1, 9); measure(0.1, 7);
measure(0.5, 51); measure(0.5, 44);

Просмотреть файл

@ -6,18 +6,3 @@ evalcx("\
f();\ f();\
f();\ f();\
", newGlobal()); ", 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();

Просмотреть файл

@ -1877,6 +1877,8 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
case Bailout_NonSimdFloat32x4Input: case Bailout_NonSimdFloat32x4Input:
case Bailout_InitialState: case Bailout_InitialState:
case Bailout_Debugger: case Bailout_Debugger:
case Bailout_UninitializedThis:
case Bailout_BadDerivedConstructorReturn:
// Do nothing. // Do nothing.
break; break;

Просмотреть файл

@ -1285,6 +1285,30 @@ BaselineCompiler::emit_JSOP_NULL()
return true; 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 bool
BaselineCompiler::emit_JSOP_THIS() BaselineCompiler::emit_JSOP_THIS()
{ {
@ -1299,6 +1323,12 @@ BaselineCompiler::emit_JSOP_THIS()
return true; return true;
} }
if (script->isDerivedClassConstructor()) {
frame.syncStack(0);
if (!emitCheckThis())
return false;
}
// Keep this value in R0 // Keep this value in R0
frame.pushThis(); frame.pushThis();
@ -2873,7 +2903,7 @@ BaselineCompiler::emitCall()
{ {
MOZ_ASSERT(IsCallPC(pc)); 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); uint32_t argc = GET_ARGC(pc);
frame.syncStack(0); frame.syncStack(0);
@ -2900,13 +2930,13 @@ BaselineCompiler::emitSpreadCall()
masm.move32(Imm32(1), R0.scratchReg()); masm.move32(Imm32(1), R0.scratchReg());
// Call IC // 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); /* isSpread = */ true);
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
return false; return false;
// Update FrameInfo. // Update FrameInfo.
bool construct = JSOp(*pc) == JSOP_SPREADNEW;
frame.popn(3 + construct); frame.popn(3 + construct);
frame.push(R0); frame.push(R0);
return true; return true;
@ -2924,6 +2954,12 @@ BaselineCompiler::emit_JSOP_NEW()
return emitCall(); return emitCall();
} }
bool
BaselineCompiler::emit_JSOP_SUPERCALL()
{
return emitCall();
}
bool bool
BaselineCompiler::emit_JSOP_FUNCALL() BaselineCompiler::emit_JSOP_FUNCALL()
{ {
@ -2960,6 +2996,12 @@ BaselineCompiler::emit_JSOP_SPREADNEW()
return emitSpreadCall(); return emitSpreadCall();
} }
bool
BaselineCompiler::emit_JSOP_SPREADSUPERCALL()
{
return emitSpreadCall();
}
bool bool
BaselineCompiler::emit_JSOP_SPREADEVAL() BaselineCompiler::emit_JSOP_SPREADEVAL()
{ {
@ -3290,6 +3332,10 @@ BaselineCompiler::emit_JSOP_DEBUGGER()
return true; return true;
} }
typedef bool (*ThrowBadDerivedReturnFn)(JSContext*, HandleValue);
static const VMFunction ThrowBadDerivedReturnInfo =
FunctionInfo<ThrowBadDerivedReturnFn>(jit::ThrowBadDerivedReturn);
typedef bool (*DebugEpilogueFn)(JSContext*, BaselineFrame*, jsbytecode*); typedef bool (*DebugEpilogueFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction DebugEpilogueInfo = static const VMFunction DebugEpilogueInfo =
FunctionInfo<DebugEpilogueFn>(jit::DebugEpilogueOnBaselineReturn); FunctionInfo<DebugEpilogueFn>(jit::DebugEpilogueOnBaselineReturn);
@ -3297,6 +3343,29 @@ static const VMFunction DebugEpilogueInfo =
bool bool
BaselineCompiler::emitReturn() 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_) { if (compileDebugInstrumentation_) {
// Move return value into the frame's rval slot. // Move return value into the frame's rval slot.
masm.storeValue(JSReturnOperand, frame.addressOfReturnValue()); masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());

Просмотреть файл

@ -201,7 +201,9 @@ namespace jit {
_(JSOP_SETRVAL) \ _(JSOP_SETRVAL) \
_(JSOP_RETRVAL) \ _(JSOP_RETRVAL) \
_(JSOP_RETURN) \ _(JSOP_RETURN) \
_(JSOP_NEWTARGET) _(JSOP_NEWTARGET) \
_(JSOP_SUPERCALL) \
_(JSOP_SPREADSUPERCALL)
class BaselineCompiler : public BaselineCompilerSpecific class BaselineCompiler : public BaselineCompilerSpecific
{ {
@ -305,6 +307,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool emitFormalArgAccess(uint32_t arg, bool get); bool emitFormalArgAccess(uint32_t arg, bool get);
bool emitUninitializedLexicalCheck(const ValueOperand& val); bool emitUninitializedLexicalCheck(const ValueOperand& val);
bool emitCheckThis();
bool addPCMappingEntry(bool addIndexEntry); bool addPCMappingEntry(bool addIndexEntry);

Просмотреть файл

@ -395,6 +395,8 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, JSScript* script,
} }
if (val.isPrimitive()) { if (val.isPrimitive()) {
if (val.isMagic(JS_UNINITIALIZED_LEXICAL))
return true;
MOZ_ASSERT(!val.isMagic()); MOZ_ASSERT(!val.isMagic());
JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType(); JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
@ -503,11 +505,16 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
{ {
// It's possible that we arrived here from bailing out of Ion, and that // 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 // Ion proved that the value is dead and optimized out. In such cases, do
// nothing. // 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)) { if (value.isMagic(JS_OPTIMIZED_OUT)) {
res.set(value); res.set(value);
return true; return true;
} }
}
RootedScript script(cx, frame->script()); RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script); jsbytecode* pc = stub->icEntry()->pc(script);
@ -516,6 +523,9 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
uint32_t argument; uint32_t argument;
if (stub->monitorsThis()) { if (stub->monitorsThis()) {
MOZ_ASSERT(pc == script->code()); MOZ_ASSERT(pc == script->code());
if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
TypeScript::SetThis(cx, script, TypeSet::UnknownType());
else
TypeScript::SetThis(cx, script, value); TypeScript::SetThis(cx, script, value);
} else if (stub->monitorsArgument(&argument)) { } else if (stub->monitorsArgument(&argument)) {
MOZ_ASSERT(pc == script->code()); MOZ_ASSERT(pc == script->code());
@ -5015,6 +5025,18 @@ TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode*
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>()); 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"); JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName/NativeGetter) stub");
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativeGlobal, current, if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativeGlobal, current,
globalLexical, getter)) 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, JSOp op, uint32_t argc, Value* vp, bool constructing, bool isSpread,
bool createSingleton, bool* handled) bool createSingleton, bool* handled)
{ {
bool isSuper = op == JSOP_SUPERCALL || op == JSOP_SPREADSUPERCALL;
if (createSingleton || op == JSOP_EVAL || op == JSOP_STRICTEVAL) if (createSingleton || op == JSOP_EVAL || op == JSOP_STRICTEVAL)
return true; return true;
@ -8729,9 +8753,11 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype)); EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
// Remember the template object associated with any script being called // 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); RootedObject templateObject(cx);
if (constructing) { if (constructing && !isSuper) {
// If we are calling a constructor for which the new script // If we are calling a constructor for which the new script
// properties analysis has not been performed yet, don't attach a // properties analysis has not been performed yet, don't attach a
// stub. After the analysis is performed, CreateThisForFunction may // 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 // Only attach a stub if the function already has a prototype and
// we can look it up without causing side effects. // we can look it up without causing side effects.
RootedObject newTarget(cx, &vp[2 + argc].toObject());
RootedValue protov(cx); 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"); JitSpew(JitSpew_BaselineIC, " Can't purely lookup function prototype");
return true; return true;
} }
if (protov.isObject()) { if (protov.isObject()) {
TaggedProto proto(&protov.toObject()); TaggedProto proto(&protov.toObject());
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, nullptr, proto, fun); ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, nullptr, proto, newTarget);
if (!group) if (!group)
return false; 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) if (!thisObject)
return false; return false;
@ -8830,7 +8857,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
} }
RootedObject templateObject(cx); RootedObject templateObject(cx);
if (MOZ_LIKELY(!isSpread)) { if (MOZ_LIKELY(!isSpread && !isSuper)) {
bool skipAttach = false; bool skipAttach = false;
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach)) if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach))
@ -9516,7 +9543,8 @@ ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<Jit
isConstructing_); 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); static const VMFunction CreateThisInfoBaseline = FunctionInfo<CreateThisFn>(CreateThis);
bool bool
@ -9610,24 +9638,31 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Stack now looks like: // Stack now looks like:
// [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader, ArgC ] // [..., 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_) { if (isSpread_) {
masm.loadValue(Address(masm.getStackPointer(), 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 { } else {
BaseValueIndex calleeSlot2(masm.getStackPointer(), argcReg, 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.loadValue(calleeSlot2, R1);
} }
masm.push(masm.extractObject(R1, ExtractTemp0)); masm.push(masm.extractObject(R1, ExtractTemp0));
if (!callVM(CreateThisInfoBaseline, masm)) if (!callVM(CreateThisInfoBaseline, masm))
return false; return false;
// Return of CreateThis must be an object. // Return of CreateThis must be an object or uninitialized.
#ifdef DEBUG #ifdef DEBUG
Label createdThisIsObject; Label createdThisOK;
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisIsObject); masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisOK);
masm.assumeUnreachable("The return of CreateThis must be an object."); masm.branchTestMagic(Assembler::Equal, JSReturnOperand, &createdThisOK);
masm.bind(&createdThisIsObject); masm.assumeUnreachable("The return of CreateThis must be an object or uninitialized.");
masm.bind(&createdThisOK);
#endif #endif
// Reset the register set from here on in. // Reset the register set from here on in.

Просмотреть файл

@ -111,7 +111,8 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
EnterJitCode enter = cx->runtime()->jitRuntime()->enterBaseline(); EnterJitCode enter = cx->runtime()->jitRuntime()->enterBaseline();
// Caller must construct |this| before invoking the Ion function. // 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); data.result.setInt32(data.numActualArgs);
{ {
@ -131,9 +132,12 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride()); MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
// Jit callers wrap primitive constructor return. // Jit callers wrap primitive constructor return, except for derived
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) // 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]; data.result = data.maxArgv[0];
}
// Release temporary buffer used for OSR into Ion. // Release temporary buffer used for OSR into Ion.
cx->runtime()->getJitRuntime(cx)->freeOsrTempData(); cx->runtime()->getJitRuntime(cx)->freeOsrTempData();
@ -306,15 +310,6 @@ CanEnterBaselineJIT(JSContext* cx, HandleScript script, InterpreterFrame* osrFra
MethodStatus MethodStatus
jit::CanEnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, bool newType) 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)) if (!CheckFrame(fp))
return Method_CantCompile; return Method_CantCompile;
@ -356,8 +351,13 @@ jit::CanEnterBaselineMethod(JSContext* cx, RunState& state)
return Method_CantCompile; return Method_CantCompile;
} }
if (!state.maybeCreateThisForConstructor(cx)) if (!state.maybeCreateThisForConstructor(cx)) {
if (cx->isThrowingOutOfMemory()) {
cx->recoverFromOutOfMemory();
return Method_Skipped; return Method_Skipped;
}
return Method_Error;
}
} else { } else {
MOZ_ASSERT(state.isExecute()); MOZ_ASSERT(state.isExecute());
ExecuteType type = state.asExecute()->type(); ExecuteType type = state.asExecute()->type();

Просмотреть файл

@ -4928,13 +4928,19 @@ CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir)
callVM(InitPropGetterSetterInfo, 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); static const VMFunction CreateThisInfoCodeGen = FunctionInfo<CreateThisFn>(CreateThis);
void void
CodeGenerator::visitCreateThis(LCreateThis* lir) CodeGenerator::visitCreateThis(LCreateThis* lir)
{ {
const LAllocation* callee = lir->getCallee(); 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()) if (callee->isConstant())
pushArg(ImmGCPtr(&callee->toConstant()->toObject())); pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
@ -4945,12 +4951,14 @@ CodeGenerator::visitCreateThis(LCreateThis* lir)
} }
static JSObject* 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 = static const VMFunction CreateThisWithProtoInfo =
FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper); FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper);
@ -4958,6 +4966,7 @@ void
CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir) CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
{ {
const LAllocation* callee = lir->getCallee(); const LAllocation* callee = lir->getCallee();
const LAllocation* newTarget = lir->getNewTarget();
const LAllocation* proto = lir->getPrototype(); const LAllocation* proto = lir->getPrototype();
if (proto->isConstant()) if (proto->isConstant())
@ -4965,6 +4974,11 @@ CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
else else
pushArg(ToRegister(proto)); pushArg(ToRegister(proto));
if (newTarget->isConstant())
pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
else
pushArg(ToRegister(newTarget));
if (callee->isConstant()) if (callee->isConstant())
pushArg(ImmGCPtr(&callee->toConstant()->toObject())); pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
else else
@ -10325,6 +10339,19 @@ CodeGenerator::visitNewTarget(LNewTarget *ins)
masm.bind(&done); 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. // Out-of-line math_random_no_outparam call for LRandom.
class OutOfLineRandom : public OutOfLineCodeBase<CodeGenerator> class OutOfLineRandom : public OutOfLineCodeBase<CodeGenerator>
{ {

Просмотреть файл

@ -335,6 +335,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitDebugger(LDebugger* ins); void visitDebugger(LDebugger* ins);
void visitNewTarget(LNewTarget* ins); void visitNewTarget(LNewTarget* ins);
void visitArrowNewTarget(LArrowNewTarget* ins); void visitArrowNewTarget(LArrowNewTarget* ins);
void visitCheckReturn(LCheckReturn* ins);
void visitCheckOverRecursed(LCheckOverRecursed* lir); void visitCheckOverRecursed(LCheckOverRecursed* lir);
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool); void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);

Просмотреть файл

@ -2547,9 +2547,12 @@ jit::CanEnter(JSContext* cx, RunState& state)
} }
if (!state.maybeCreateThisForConstructor(cx)) { if (!state.maybeCreateThisForConstructor(cx)) {
if (cx->isThrowingOutOfMemory()) {
cx->recoverFromOutOfMemory(); cx->recoverFromOutOfMemory();
return Method_Skipped; return Method_Skipped;
} }
return Method_Error;
}
} }
// If --ion-eager is used, compile with Baseline first, so that we // If --ion-eager is used, compile with Baseline first, so that we
@ -2659,7 +2662,8 @@ EnterIon(JSContext* cx, EnterJitData& data)
EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon(); EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
// Caller must construct |this| before invoking the Ion function. // 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); data.result.setInt32(data.numActualArgs);
{ {
@ -2672,9 +2676,13 @@ EnterIon(JSContext* cx, EnterJitData& data)
MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride()); MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
// Jit callers wrap primitive constructor return. // Jit callers wrap primitive constructor return, except for derived class constructors.
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) if (!data.result.isMagic() && data.constructing &&
data.result.isPrimitive())
{
MOZ_ASSERT(data.maxArgv[0].isObject());
data.result = data.maxArgv[0]; data.result = data.maxArgv[0];
}
// Release temporary buffer used for OSR into Ion. // Release temporary buffer used for OSR into Ion.
cx->runtime()->getJitRuntime(cx)->freeOsrTempData(); cx->runtime()->getJitRuntime(cx)->freeOsrTempData();

Просмотреть файл

@ -1867,7 +1867,8 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_CALL: case JSOP_CALL:
case JSOP_NEW: 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_EVAL:
case JSOP_STRICTEVAL: case JSOP_STRICTEVAL:
@ -4469,6 +4470,15 @@ IonBuilder::processReturn(JSOp op)
MOZ_CRASH("unknown return 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); MReturn* ret = MReturn::New(alloc(), def);
current->end(ret); current->end(ret);
@ -4944,7 +4954,7 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target)
// Create new |this| on the caller-side for inlined constructors. // Create new |this| on the caller-side for inlined constructors.
if (callInfo.constructing()) { if (callInfo.constructing()) {
MDefinition* thisDefn = createThis(target, callInfo.fun()); MDefinition* thisDefn = createThis(target, callInfo.fun(), callInfo.getNewTarget());
if (!thisDefn) if (!thisDefn)
return false; return false;
callInfo.setThis(thisDefn); callInfo.setThis(thisDefn);
@ -6038,7 +6048,7 @@ IonBuilder::createCallObject(MDefinition* callee, MDefinition* scope)
} }
MDefinition* MDefinition*
IonBuilder::createThisScripted(MDefinition* callee) IonBuilder::createThisScripted(MDefinition* callee, MDefinition* newTarget)
{ {
// Get callee.prototype. // Get callee.prototype.
// //
@ -6053,12 +6063,12 @@ IonBuilder::createThisScripted(MDefinition* callee)
// and thus invalidation. // and thus invalidation.
MInstruction* getProto; MInstruction* getProto;
if (!invalidatedIdempotentCache()) { if (!invalidatedIdempotentCache()) {
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), callee, names().prototype, MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), newTarget, names().prototype,
/* monitored = */ false); /* monitored = */ false);
getPropCache->setIdempotent(); getPropCache->setIdempotent();
getProto = getPropCache; getProto = getPropCache;
} else { } else {
MCallGetProperty* callGetProp = MCallGetProperty::New(alloc(), callee, names().prototype, MCallGetProperty* callGetProp = MCallGetProperty::New(alloc(), newTarget, names().prototype,
/* callprop = */ false); /* callprop = */ false);
callGetProp->setIdempotent(); callGetProp->setIdempotent();
getProto = callGetProp; getProto = callGetProp;
@ -6066,7 +6076,7 @@ IonBuilder::createThisScripted(MDefinition* callee)
current->add(getProto); current->add(getProto);
// Create this from prototype // Create this from prototype
MCreateThisWithProto* createThis = MCreateThisWithProto::New(alloc(), callee, getProto); MCreateThisWithProto* createThis = MCreateThisWithProto::New(alloc(), callee, newTarget, getProto);
current->add(createThis); current->add(createThis);
return createThis; return createThis;
@ -6131,6 +6141,8 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
return nullptr; return nullptr;
JSObject* templateObject = inspector->getTemplateObject(pc); JSObject* templateObject = inspector->getTemplateObject(pc);
if (!templateObject)
return nullptr;
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>()) if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>())
return nullptr; return nullptr;
@ -6181,14 +6193,14 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
} }
MDefinition* MDefinition*
IonBuilder::createThis(JSFunction* target, MDefinition* callee) IonBuilder::createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget)
{ {
// Create |this| for unknown target. // Create |this| for unknown target.
if (!target) { if (!target) {
if (MDefinition* createThis = createThisScriptedBaseline(callee)) if (MDefinition* createThis = createThisScriptedBaseline(callee))
return createThis; return createThis;
MCreateThis* createThis = MCreateThis::New(alloc(), callee); MCreateThis* createThis = MCreateThis::New(alloc(), callee, newTarget);
current->add(createThis); current->add(createThis);
return createThis; return createThis;
} }
@ -6203,6 +6215,11 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee)
return magic; return magic;
} }
if (target->isDerivedClassConstructor()) {
MOZ_ASSERT(target->isClassConstructor());
return constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
}
// Try baking in the prototype. // Try baking in the prototype.
if (MDefinition* createThis = createThisScriptedSingleton(target, callee)) if (MDefinition* createThis = createThisScriptedSingleton(target, callee))
return createThis; return createThis;
@ -6210,7 +6227,7 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee)
if (MDefinition* createThis = createThisScriptedBaseline(callee)) if (MDefinition* createThis = createThisScriptedBaseline(callee))
return createThis; return createThis;
return createThisScripted(callee); return createThisScripted(callee, newTarget);
} }
bool bool
@ -6600,7 +6617,7 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo)
// Inline the constructor on the caller-side. // Inline the constructor on the caller-side.
if (callInfo.constructing()) { if (callInfo.constructing()) {
MDefinition* create = createThis(target, callInfo.fun()); MDefinition* create = createThis(target, callInfo.fun(), callInfo.getNewTarget());
if (!create) { if (!create) {
abort("Failure inlining constructor for call."); abort("Failure inlining constructor for call.");
return nullptr; return nullptr;
@ -12749,10 +12766,22 @@ IonBuilder::jsop_this()
if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) { if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
// No need to wrap primitive |this| in strict mode or self-hosted code. // 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; return true;
} }
MOZ_ASSERT(!info().funMaybeLazy()->isClassConstructor());
if (thisTypes && (thisTypes->getKnownMIRType() == MIRType_Object || if (thisTypes && (thisTypes->getKnownMIRType() == MIRType_Object ||
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))) (thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject())))
{ {

Просмотреть файл

@ -380,10 +380,10 @@ class IonBuilder
JSObject* getSingletonPrototype(JSFunction* target); JSObject* getSingletonPrototype(JSFunction* target);
MDefinition* createThisScripted(MDefinition* callee); MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee); MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee);
MDefinition* createThisScriptedBaseline(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* createDeclEnvObject(MDefinition* callee, MDefinition* scopeObj);
MInstruction* createCallObject(MDefinition* callee, MDefinition* scopeObj); MInstruction* createCallObject(MDefinition* callee, MDefinition* scopeObj);

Просмотреть файл

@ -111,8 +111,13 @@ enum BailoutKind
// We hit a |debugger;| statement. // We hit a |debugger;| statement.
Bailout_Debugger, 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. // Bailouts caused by invalid assumptions based on Baseline code.
// Causes immediate invalidation. // Causes immediate invalidation.
@ -151,7 +156,7 @@ enum BailoutKind
Bailout_UninitializedLexical, Bailout_UninitializedLexical,
// A bailout to baseline from Ion on exception to handle Debugger hooks. // A bailout to baseline from Ion on exception to handle Debugger hooks.
Bailout_IonExceptionDebugMode, Bailout_IonExceptionDebugMode
}; };
inline const char* inline const char*
@ -209,6 +214,10 @@ BailoutKindString(BailoutKind kind)
return "Bailout_InitialState"; return "Bailout_InitialState";
case Bailout_Debugger: case Bailout_Debugger:
return "Bailout_Debugger"; return "Bailout_Debugger";
case Bailout_UninitializedThis:
return "Bailout_UninitializedThis";
case Bailout_BadDerivedConstructorReturn:
return "Bailout_BadDerivedConstructorReturn";
// Bailouts caused by invalid assumptions. // Bailouts caused by invalid assumptions.
case Bailout_OverflowInvalidate: case Bailout_OverflowInvalidate:

Просмотреть файл

@ -328,6 +328,7 @@ LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
{ {
LCreateThisWithProto* lir = LCreateThisWithProto* lir =
new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()), new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
useRegisterOrConstantAtStart(ins->getNewTarget()),
useRegisterOrConstantAtStart(ins->getPrototype())); useRegisterOrConstantAtStart(ins->getPrototype()));
defineReturn(lir, ins); defineReturn(lir, ins);
assignSafepoint(lir, ins); assignSafepoint(lir, ins);
@ -336,7 +337,8 @@ LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
void void
LIRGenerator::visitCreateThis(MCreateThis* ins) 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); defineReturn(lir, ins);
assignSafepoint(lir, ins); assignSafepoint(lir, ins);
} }
@ -4258,7 +4260,7 @@ LIRGenerator::visitLexicalCheck(MLexicalCheck* ins)
MOZ_ASSERT(input->type() == MIRType_Value); MOZ_ASSERT(input->type() == MIRType_Value);
LLexicalCheck* lir = new(alloc()) LLexicalCheck(); LLexicalCheck* lir = new(alloc()) LLexicalCheck();
useBox(lir, LLexicalCheck::Input, input); useBox(lir, LLexicalCheck::Input, input);
assignSnapshot(lir, Bailout_UninitializedLexical); assignSnapshot(lir, ins->bailoutKind());
add(lir, ins); add(lir, ins);
redefine(ins, input); redefine(ins, input);
} }
@ -4293,6 +4295,22 @@ LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins)
define(new(alloc()) LAtomicIsLockFree(useRegister(ins->input())), 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 static void
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint) SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
{ {

Просмотреть файл

@ -306,6 +306,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitNewTarget(MNewTarget* ins); void visitNewTarget(MNewTarget* ins);
void visitArrowNewTarget(MArrowNewTarget* ins); void visitArrowNewTarget(MArrowNewTarget* ins);
void visitAtomicIsLockFree(MAtomicIsLockFree* ins); void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
void visitCheckReturn(MCheckReturn* ins);
}; };
} // namespace jit } // namespace jit

Просмотреть файл

@ -4613,11 +4613,11 @@ class MCreateThisWithTemplate
// Caller-side allocation of |this| for |new|: // Caller-side allocation of |this| for |new|:
// Given a prototype operand, construct |this| for JSOP_NEW. // Given a prototype operand, construct |this| for JSOP_NEW.
class MCreateThisWithProto class MCreateThisWithProto
: public MBinaryInstruction, : public MTernaryInstruction,
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
{ {
MCreateThisWithProto(MDefinition* callee, MDefinition* prototype) MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
: MBinaryInstruction(callee, prototype) : MTernaryInstruction(callee, newTarget, prototype)
{ {
setResultType(MIRType_Object); setResultType(MIRType_Object);
} }
@ -4625,17 +4625,20 @@ class MCreateThisWithProto
public: public:
INSTRUCTION_HEADER(CreateThisWithProto) INSTRUCTION_HEADER(CreateThisWithProto)
static MCreateThisWithProto* New(TempAllocator& alloc, MDefinition* callee, 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 { MDefinition* getCallee() const {
return getOperand(0); return getOperand(0);
} }
MDefinition* getPrototype() const { MDefinition* getNewTarget() const {
return getOperand(1); return getOperand(1);
} }
MDefinition* getPrototype() const {
return getOperand(2);
}
// Although creation of |this| modifies global state, it is safely repeatable. // Although creation of |this| modifies global state, it is safely repeatable.
AliasSet getAliasSet() const override { AliasSet getAliasSet() const override {
@ -4649,25 +4652,28 @@ class MCreateThisWithProto
// Caller-side allocation of |this| for |new|: // Caller-side allocation of |this| for |new|:
// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING). // Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
class MCreateThis class MCreateThis
: public MUnaryInstruction, : public MBinaryInstruction,
public ObjectPolicy<0>::Data public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
{ {
explicit MCreateThis(MDefinition* callee) explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
: MUnaryInstruction(callee) : MBinaryInstruction(callee, newTarget)
{ {
setResultType(MIRType_Value); setResultType(MIRType_Value);
} }
public: public:
INSTRUCTION_HEADER(CreateThis) 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 { MDefinition* getCallee() const {
return getOperand(0); return getOperand(0);
} }
MDefinition* getNewTarget() const {
return getOperand(0);
}
// Although creation of |this| modifies global state, it is safely repeatable. // Although creation of |this| modifies global state, it is safely repeatable.
AliasSet getAliasSet() const override { AliasSet getAliasSet() const override {
@ -7230,8 +7236,10 @@ class MLexicalCheck
: public MUnaryInstruction, : public MUnaryInstruction,
public BoxPolicy<0>::Data public BoxPolicy<0>::Data
{ {
explicit MLexicalCheck(MDefinition* input) BailoutKind kind_;
: MUnaryInstruction(input) explicit MLexicalCheck(MDefinition* input, BailoutKind kind)
: MUnaryInstruction(input),
kind_(kind)
{ {
setResultType(MIRType_Value); setResultType(MIRType_Value);
setResultTypeSet(input->resultTypeSet()); setResultTypeSet(input->resultTypeSet());
@ -7242,8 +7250,9 @@ class MLexicalCheck
public: public:
INSTRUCTION_HEADER(LexicalCheck) INSTRUCTION_HEADER(LexicalCheck)
static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input) { static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input,
return new(alloc) MLexicalCheck(input); BailoutKind kind = Bailout_UninitializedLexical) {
return new(alloc) MLexicalCheck(input, kind);
} }
AliasSet getAliasSet() const override { AliasSet getAliasSet() const override {
@ -7254,6 +7263,10 @@ class MLexicalCheck
return getOperand(0); return getOperand(0);
} }
BailoutKind bailoutKind() const {
return kind_;
}
bool congruentTo(const MDefinition* ins) const override { bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins); 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 // 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 // the warm-up counter surpasses the threshold. Upon hit it will recompile the
// outermost script (i.e. not the inlined script). // outermost script (i.e. not the inlined script).

Просмотреть файл

@ -277,7 +277,8 @@ namespace jit {
_(GlobalNameConflictsCheck) \ _(GlobalNameConflictsCheck) \
_(Debugger) \ _(Debugger) \
_(NewTarget) \ _(NewTarget) \
_(ArrowNewTarget) _(ArrowNewTarget) \
_(CheckReturn)
// Forward declarations of MIR types. // Forward declarations of MIR types.
#define FORWARD_DECLARE(op) class M##op; #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>, IntPolicy<2> >) \
_(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \ _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \
_(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<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>, IntPolicy<1>, IntPolicy<2>>) \
_(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \ _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \
_(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \ _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \

Просмотреть файл

@ -565,7 +565,7 @@ GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rva
} }
bool bool
CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval) CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval)
{ {
rval.set(MagicValue(JS_IS_CONSTRUCTING)); rval.set(MagicValue(JS_IS_CONSTRUCTING));
@ -575,12 +575,16 @@ CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval)
JSScript* script = fun->getOrCreateScript(cx); JSScript* script = fun->getOrCreateScript(cx);
if (!script || !script->ensureHasTypes(cx)) if (!script || !script->ensureHasTypes(cx))
return false; return false;
JSObject* thisObj = CreateThisForFunction(cx, callee, GenericObject); if (script->isDerivedClassConstructor()) {
rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));
} else {
JSObject* thisObj = CreateThisForFunction(cx, callee, newTarget, GenericObject);
if (!thisObj) if (!thisObj)
return false; return false;
rval.set(ObjectValue(*thisObj)); rval.set(ObjectValue(*thisObj));
} }
} }
}
return true; return true;
} }
@ -1291,5 +1295,18 @@ ThrowUninitializedLexical(JSContext* cx)
return false; 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 jit
} // namespace js } // 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 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); void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
@ -734,6 +734,8 @@ IonMarkFunction(MIRType type)
bool ObjectIsCallable(JSObject* obj); bool ObjectIsCallable(JSObject* obj);
bool ThrowUninitializedLexical(JSContext* cx); bool ThrowUninitializedLexical(JSContext* cx);
bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
} // namespace jit } // namespace jit
} // namespace js } // namespace js

Просмотреть файл

@ -13,6 +13,7 @@
#include "jit/arm64/vixl/Debugger-vixl.h" #include "jit/arm64/vixl/Debugger-vixl.h"
#endif #endif
#include "jit/MacroAssembler-inl.h"
using namespace js; using namespace js;
using namespace js::jit; using namespace js::jit;

Просмотреть файл

@ -5,10 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/arm64/MoveEmitter-arm64.h" #include "jit/arm64/MoveEmitter-arm64.h"
#include "jit/MacroAssembler-inl.h"
using namespace js; using namespace js;
using namespace js::jit; 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 void
MoveEmitterARM64::emit(const MoveResolver& moves) MoveEmitterARM64::emit(const MoveResolver& moves)
{ {

Просмотреть файл

@ -35,13 +35,7 @@ class MoveEmitterARM64
} }
MemOperand cycleSlot(); MemOperand cycleSlot();
MemOperand toMemOperand(const MoveOperand& operand) const { 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());
}
ARMRegister toARMReg32(const MoveOperand& operand) const { ARMRegister toARMReg32(const MoveOperand& operand) const {
MOZ_ASSERT(operand.isGeneralReg()); MOZ_ASSERT(operand.isGeneralReg());
return ARMRegister(operand.reg(), 32); 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()) { switch (BranchType()) {
case CondBranchType: return ImmCondBranch(); case CondBranchType: return ImmCondBranch();
case UncondBranchType: return ImmUncondBranch(); 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, // Allocate an object for |new| on the caller-side,
// when there is no templateObject or prototype known // 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: public:
LIR_HEADER(CreateThis) LIR_HEADER(CreateThis)
explicit LCreateThis(const LAllocation& callee) LCreateThis(const LAllocation& callee, const LAllocation& newTarget)
{ {
setOperand(0, callee); setOperand(0, callee);
setOperand(1, newTarget);
} }
const LAllocation* getCallee() { const LAllocation* getCallee() {
return getOperand(0); return getOperand(0);
} }
const LAllocation* getNewTarget() {
return getOperand(1);
}
MCreateThis* mir() const { MCreateThis* mir() const {
return mir_->toCreateThis(); return mir_->toCreateThis();
@ -1321,23 +1325,28 @@ class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0>
// Allocate an object for |new| on the caller-side, // Allocate an object for |new| on the caller-side,
// when the prototype is known. // when the prototype is known.
class LCreateThisWithProto : public LCallInstructionHelper<1, 2, 0> class LCreateThisWithProto : public LCallInstructionHelper<1, 3, 0>
{ {
public: public:
LIR_HEADER(CreateThisWithProto) LIR_HEADER(CreateThisWithProto)
LCreateThisWithProto(const LAllocation& callee, const LAllocation& prototype) LCreateThisWithProto(const LAllocation& callee, const LAllocation& newTarget,
const LAllocation& prototype)
{ {
setOperand(0, callee); setOperand(0, callee);
setOperand(1, prototype); setOperand(1, newTarget);
setOperand(2, prototype);
} }
const LAllocation* getCallee() { const LAllocation* getCallee() {
return getOperand(0); return getOperand(0);
} }
const LAllocation* getPrototype() { const LAllocation* getNewTarget() {
return getOperand(1); return getOperand(1);
} }
const LAllocation* getPrototype() {
return getOperand(2);
}
MCreateThis* mir() const { MCreateThis* mir() const {
return mir_->toCreateThis(); 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 jit
} // namespace js } // namespace js

Просмотреть файл

@ -368,6 +368,7 @@
_(GlobalNameConflictsCheck) \ _(GlobalNameConflictsCheck) \
_(Debugger) \ _(Debugger) \
_(NewTarget) \ _(NewTarget) \
_(ArrowNewTarget) _(ArrowNewTarget) \
_(CheckReturn)
#endif /* jit_shared_LOpcodes_shared_h */ #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_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_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_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 // JSON
MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") 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_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'") 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_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_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_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list")
MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression") 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 // Super
MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving '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 // Modules
MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *") 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; 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_PUBLIC_API(void)
JS::SetAsmJSCacheOps(JSRuntime* rt, const JS::AsmJSCacheOps* ops) 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) extern JS_PUBLIC_API(bool)
JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result); 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*) extern JS_PUBLIC_API(JSObject*)
JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args); JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);

Просмотреть файл

@ -374,6 +374,12 @@ struct JSCompartment
js::NewObjectMetadataState objectMetadataState; js::NewObjectMetadataState objectMetadataState;
public: 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>(); } bool hasObjectPendingMetadata() const { return objectMetadataState.is<js::PendingMetadata>(); }
void setObjectPendingMetadata(JSContext* cx, JSObject* obj) { void setObjectPendingMetadata(JSContext* cx, JSObject* obj) {

Просмотреть файл

@ -156,6 +156,7 @@ class JSFunction : public js::NativeObject
nonLazyScript()->funHasExtensibleScope() || nonLazyScript()->funHasExtensibleScope() ||
nonLazyScript()->funNeedsDeclEnvObject() || nonLazyScript()->funNeedsDeclEnvObject() ||
nonLazyScript()->needsHomeObject() || nonLazyScript()->needsHomeObject() ||
nonLazyScript()->isDerivedClassConstructor() ||
isGenerator(); isGenerator();
} }
@ -516,6 +517,16 @@ class JSFunction : public js::NativeObject
u.n.jitinfo = data; 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 unsigned offsetOfNativeOrScript() {
static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_), static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
"native and script pointers must be in the same spot " "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()); return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
} }
static uint64_t void
random_generateSeed() js::random_generateSeed(uint64_t* seedBuffer, size_t length)
{ {
union { if (length == 0)
uint8_t u8[8]; return;
uint32_t u32[2];
uint64_t u64;
} seed;
seed.u64 = 0;
#if defined(XP_WIN) #if defined(XP_WIN)
/* /*
@ -760,6 +756,12 @@ random_generateSeed()
if (oldWay && !newWay) if (oldWay && !newWay)
MOZ_CRASH(); MOZ_CRASH();
union {
uint32_t u32[2];
uint64_t u64;
} seed;
seed.u64 = 0;
errno_t error = rand_s(&seed.u32[0]); errno_t error = rand_s(&seed.u32[0]);
if (oldWay) if (oldWay)
@ -771,24 +773,44 @@ random_generateSeed()
error = rand_s(&seed.u32[1]); error = rand_s(&seed.u32[1]);
MOZ_ASSERT(error == 0, "rand_s() error?!"); 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) #elif defined(HAVE_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[0] = arc4random();
seed.u32[1] = arc4random(); seed.u32[1] = arc4random();
seedBuffer[i] = seed.u64 ^ PRMJ_Now();
}
#elif defined(XP_UNIX) #elif defined(XP_UNIX)
int fd = open("/dev/urandom", O_RDONLY); int fd = open("/dev/urandom", O_RDONLY);
MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom?!"); MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom?!");
if (fd >= 0) { if (fd >= 0) {
ssize_t nread = read(fd, seed.u8, mozilla::ArrayLength(seed.u8)); ssize_t size = length * sizeof(seedBuffer[0]);
MOZ_ASSERT(nread == 8, "Can't read /dev/urandom?!"); ssize_t nread = read(fd, (char *) seedBuffer, size);
MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
mozilla::unused << nread; mozilla::unused << nread;
close(fd); close(fd);
} }
#else #else
# error "Platform needs to implement random_generateSeed()" # error "Platform needs to implement random_generateSeed()"
#endif #endif
seed.u64 ^= PRMJ_Now();
return seed.u64;
} }
/* /*
@ -798,7 +820,8 @@ void
js::random_initState(uint64_t* rngState) js::random_initState(uint64_t* rngState)
{ {
/* Our PRNG only uses 48 bits, so squeeze our entropy into those bits. */ /* 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); seed ^= (seed >> 16);
*rngState = (seed ^ RNG_MULTIPLIER) & RNG_MASK; *rngState = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
} }

Просмотреть файл

@ -109,6 +109,13 @@ class MathCache
extern JSObject* extern JSObject*
InitMathClass(JSContext* cx, HandleObject obj); 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 extern void
random_initState(uint64_t* rngState); random_initState(uint64_t* rngState);

Просмотреть файл

@ -967,14 +967,14 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
} }
JSObject* JSObject*
js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject proto, js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject newTarget,
NewObjectKind newKind /* = GenericObject */) HandleObject proto, NewObjectKind newKind /* = GenericObject */)
{ {
RootedObject res(cx); RootedObject res(cx);
if (proto) { if (proto) {
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto), RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
&callee->as<JSFunction>())); newTarget));
if (!group) if (!group)
return nullptr; return nullptr;
@ -986,7 +986,7 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj
// The script was analyzed successfully and may have changed // The script was analyzed successfully and may have changed
// the new type table, so refetch the group. // the new type table, so refetch the group.
group = ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto), group = ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
&callee->as<JSFunction>()); newTarget);
MOZ_ASSERT(group && group->newScript()); MOZ_ASSERT(group && group->newScript());
} }
} }
@ -1007,15 +1007,16 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj
} }
JSObject* JSObject*
js::CreateThisForFunction(JSContext* cx, HandleObject callee, NewObjectKind newKind) js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTarget,
NewObjectKind newKind)
{ {
RootedValue protov(cx); RootedValue protov(cx);
if (!GetProperty(cx, callee, callee, cx->names().prototype, &protov)) if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov))
return nullptr; return nullptr;
RootedObject proto(cx); RootedObject proto(cx);
if (protov.isObject()) if (protov.isObject())
proto = &protov.toObject(); proto = &protov.toObject();
JSObject* obj = CreateThisForFunctionWithProto(cx, callee, proto, newKind); JSObject* obj = CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind);
if (obj && newKind == SingletonObject) { if (obj && newKind == SingletonObject) {
RootedPlainObject nobj(cx, &obj->as<PlainObject>()); 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 // immutable-prototype behavior is enforced; if it's false, behavior is not
// enforced, and immutable-prototype bits stored on objects are completely // enforced, and immutable-prototype bits stored on objects are completely
// ignored. // ignored.
static const bool ImmutablePrototypesEnabled = true; static const bool ImmutablePrototypesEnabled = false;
JS_FRIEND_API(bool) JS_FRIEND_API(bool)
JS_ImmutablePrototypesEnabled() JS_ImmutablePrototypesEnabled()
@ -3340,6 +3341,7 @@ JSObject::dump()
if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto"); if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto");
if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access"); if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access");
if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared"); if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared");
if (!obj->hasLazyPrototype() && obj->nonLazyPrototypeIsImmutable()) fprintf(stderr, " immutable_prototype");
if (obj->isNative()) { if (obj->isNative()) {
NativeObject* nobj = &obj->as<NativeObject>(); 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, // Specialized call for constructing |this| with a known function callee,
// and a known prototype. // and a known prototype.
extern JSObject* extern JSObject*
CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject proto, CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject newTarget,
NewObjectKind newKind = GenericObject); HandleObject proto, NewObjectKind newKind = GenericObject);
// Specialized call for constructing |this| with a known function callee. // Specialized call for constructing |this| with a known function callee.
extern JSObject* 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|. // Generic call for constructing |this|.
extern JSObject* extern JSObject*

Просмотреть файл

@ -125,6 +125,7 @@ js::StackUses(JSScript* script, jsbytecode* pc)
case JSOP_POPN: case JSOP_POPN:
return GET_UINT16(pc); return GET_UINT16(pc);
case JSOP_NEW: case JSOP_NEW:
case JSOP_SUPERCALL:
return 2 + GET_ARGC(pc) + 1; return 2 + GET_ARGC(pc) + 1;
default: default:
/* stack: fun, this, [argc arguments] */ /* stack: fun, this, [argc arguments] */

Просмотреть файл

@ -109,30 +109,53 @@ enum JSShellExitCode {
EXITCODE_TIMEOUT = 6 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 * Note: This limit should match the stack limit set by the browser in
* js/xpconnect/src/XPCJSRuntime.cpp * js/xpconnect/src/XPCJSRuntime.cpp
*/ */
#if defined(MOZ_ASAN) || (defined(DEBUG) && !defined(XP_WIN)) #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 #else
static size_t gMaxStackSize = 128 * sizeof(size_t) * 1024; static const size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
#endif #endif
/* /*
* Limit the timeout to 30 minutes to prevent an overflow on platfoms * Limit the timeout to 30 minutes to prevent an overflow on platfoms
* that represent the time internally in microseconds using 32-bit int. * that represent the time internally in microseconds using 32-bit int.
*/ */
static double MAX_TIMEOUT_INTERVAL = 1800.0; static const double MAX_TIMEOUT_INTERVAL = 1800.0;
static double gTimeoutInterval = -1.0;
static Atomic<bool> gServiceInterrupt;
static JS::PersistentRootedValue gInterruptFunc;
static bool gLastWarningEnabled = false; // Per-runtime shell state.
static JS::PersistentRootedValue gLastWarning; 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 enableCodeCoverage = false;
static bool enableDisassemblyDumps = false; static bool enableDisassemblyDumps = false;
static bool offthreadCompilation = false; static bool offthreadCompilation = false;
@ -144,11 +167,22 @@ static bool enableUnboxedArrays = false;
#ifdef JS_GC_ZEAL #ifdef JS_GC_ZEAL
static char gZealStr[128]; static char gZealStr[128];
#endif #endif
static bool printTiming = false; static bool printTiming = false;
static const char* jsCacheDir = nullptr; static const char* jsCacheDir = nullptr;
static const char* jsCacheAsmJSPath = 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); mozilla::Atomic<bool> jsCacheOpened(false);
static bool static bool
@ -158,7 +192,7 @@ static bool
InitWatchdog(JSRuntime* rt); InitWatchdog(JSRuntime* rt);
static void static void
KillWatchdog(); KillWatchdog(JSRuntime *rt);
static bool static bool
ScheduleWatchdog(JSRuntime* rt, double t); ScheduleWatchdog(JSRuntime* rt, double t);
@ -166,33 +200,6 @@ ScheduleWatchdog(JSRuntime* rt, double t);
static void static void
CancelExecution(JSRuntime* rt); 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* static JSContext*
NewContext(JSRuntime* rt); NewContext(JSRuntime* rt);
@ -267,6 +274,36 @@ extern JS_EXPORT_API(void) add_history(char* line);
} // extern "C" } // extern "C"
#endif #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* static char*
GetLine(FILE* file, const char * prompt) GetLine(FILE* file, const char * prompt)
{ {
@ -370,17 +407,18 @@ GetContextData(JSContext* cx)
static bool static bool
ShellInterruptCallback(JSContext* cx) ShellInterruptCallback(JSContext* cx)
{ {
if (!gServiceInterrupt) ShellRuntime* sr = GetShellRuntime(cx);
if (!sr->serviceInterrupt)
return true; 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. // true to distinguish watchdog or user triggered interrupts.
// Do this first to prevent other interrupts that may occur while the // Do this first to prevent other interrupts that may occur while the
// user-supplied callback is executing from re-entering the handler. // user-supplied callback is executing from re-entering the handler.
gServiceInterrupt = false; sr->serviceInterrupt = false;
bool result; bool result;
RootedValue interruptFunc(cx, gInterruptFunc); RootedValue interruptFunc(cx, sr->interruptFunc);
if (!interruptFunc.isNull()) { if (!interruptFunc.isNull()) {
JS::AutoSaveExceptionState savedExc(cx); JS::AutoSaveExceptionState savedExc(cx);
JSAutoCompartment ac(cx, &interruptFunc.toObject()); JSAutoCompartment ac(cx, &interruptFunc.toObject());
@ -398,8 +436,8 @@ ShellInterruptCallback(JSContext* cx)
result = false; result = false;
} }
if (!result && gExitCode == 0) if (!result && sr->exitCode == 0)
gExitCode = EXITCODE_TIMEOUT; sr->exitCode = EXITCODE_TIMEOUT;
return result; return result;
} }
@ -432,6 +470,8 @@ SkipUTF8BOM(FILE* file)
static void static void
RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly) RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
SkipUTF8BOM(file); SkipUTF8BOM(file);
// To support the UNIX #! shell hack, gobble the first line if it starts // 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) .setIsRunOnce(true)
.setNoScriptRval(true); .setNoScriptRval(true);
gGotError = false; sr->gotError = false;
(void) JS::Compile(cx, options, file, &script); (void) JS::Compile(cx, options, file, &script);
MOZ_ASSERT_IF(!script, gGotError); MOZ_ASSERT_IF(!script, sr->gotError);
} }
#ifdef DEBUG #ifdef DEBUG
@ -467,8 +507,8 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
#endif #endif
if (script && !compileOnly) { if (script && !compileOnly) {
if (!JS_ExecuteScript(cx, script)) { if (!JS_ExecuteScript(cx, script)) {
if (!gQuitting && gExitCode != EXITCODE_TIMEOUT) if (!sr->quitting && sr->exitCode != EXITCODE_TIMEOUT)
gExitCode = EXITCODE_RUNTIME_ERROR; sr->exitCode = EXITCODE_RUNTIME_ERROR;
} }
int64_t t2 = PRMJ_Now() - t1; int64_t t2 = PRMJ_Now() - t1;
if (printTiming) if (printTiming)
@ -514,6 +554,7 @@ EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
static void static void
ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly) ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
int lineno = 1; int lineno = 1;
bool hitEOF = false; bool hitEOF = false;
@ -529,7 +570,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
CharBuffer buffer(cx); CharBuffer buffer(cx);
do { do {
ScheduleWatchdog(cx->runtime(), -1); ScheduleWatchdog(cx->runtime(), -1);
gServiceInterrupt = false; sr->serviceInterrupt = false;
errno = 0; errno = 0;
char* line = GetLine(in, startline == lineno ? "js> " : ""); char* line = GetLine(in, startline == lineno ? "js> " : "");
@ -546,7 +587,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
return; return;
lineno++; lineno++;
if (!ScheduleWatchdog(cx->runtime(), gTimeoutInterval)) { if (!ScheduleWatchdog(cx->runtime(), sr->timeoutInterval)) {
hitEOF = true; hitEOF = true;
break; break;
} }
@ -561,7 +602,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
// Catch the error, report it, and keep going. // Catch the error, report it, and keep going.
JS_ReportPendingException(cx); JS_ReportPendingException(cx);
} }
} while (!hitEOF && !gQuitting); } while (!hitEOF && !sr->quitting);
fprintf(out, "\n"); fprintf(out, "\n");
} }
@ -1543,6 +1584,8 @@ Help(JSContext* cx, unsigned argc, Value* vp);
static bool static bool
Quit(JSContext* cx, unsigned argc, Value* vp) Quit(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
#ifdef JS_MORE_DETERMINISTIC #ifdef JS_MORE_DETERMINISTIC
// Print a message to stderr in more-deterministic builds to help jsfunfuzz // Print a message to stderr in more-deterministic builds to help jsfunfuzz
// find uncatchable-exception bugs. // find uncatchable-exception bugs.
@ -1564,8 +1607,8 @@ Quit(JSContext* cx, unsigned argc, Value* vp)
return false; return false;
} }
gExitCode = code; sr->exitCode = code;
gQuitting = true; sr->quitting = true;
return false; return false;
} }
@ -2545,9 +2588,25 @@ WorkerMain(void* arg)
js_delete(input); js_delete(input);
return; 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); JS_SetErrorReporter(rt, my_ErrorReporter);
SetWorkerRuntimeOptions(rt); SetWorkerRuntimeOptions(rt);
if (!InitWatchdog(rt)) {
JS_DestroyRuntime(rt);
js_delete(input);
return;
}
JSContext* cx = NewContext(rt); JSContext* cx = NewContext(rt);
if (!cx) { if (!cx) {
JS_DestroyRuntime(rt); JS_DestroyRuntime(rt);
@ -2653,6 +2712,7 @@ IsBefore(int64_t t1, int64_t t2)
static bool static bool
Sleep_fn(JSContext* cx, unsigned argc, Value* vp) Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
int64_t t_ticks; int64_t t_ticks;
@ -2673,61 +2733,63 @@ Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
? 0 ? 0
: int64_t(PRMJ_USEC_PER_SEC * t_secs); : int64_t(PRMJ_USEC_PER_SEC * t_secs);
} }
PR_Lock(gWatchdogLock); PR_Lock(sr->watchdogLock);
int64_t to_wakeup = PRMJ_Now() + t_ticks; int64_t to_wakeup = PRMJ_Now() + t_ticks;
for (;;) { for (;;) {
PR_WaitCondVar(gSleepWakeup, PR_MillisecondsToInterval(t_ticks / 1000)); PR_WaitCondVar(sr->sleepWakeup, PR_MillisecondsToInterval(t_ticks / 1000));
if (gServiceInterrupt) if (sr->serviceInterrupt)
break; break;
int64_t now = PRMJ_Now(); int64_t now = PRMJ_Now();
if (!IsBefore(now, to_wakeup)) if (!IsBefore(now, to_wakeup))
break; break;
t_ticks = to_wakeup - now; t_ticks = to_wakeup - now;
} }
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
args.rval().setUndefined(); args.rval().setUndefined();
return !gServiceInterrupt; return !sr->serviceInterrupt;
} }
static bool static bool
InitWatchdog(JSRuntime* rt) InitWatchdog(JSRuntime* rt)
{ {
MOZ_ASSERT(!gWatchdogThread); ShellRuntime* sr = GetShellRuntime(rt);
gWatchdogLock = PR_NewLock(); MOZ_ASSERT(!sr->watchdogThread);
if (gWatchdogLock) { sr->watchdogLock = PR_NewLock();
gWatchdogWakeup = PR_NewCondVar(gWatchdogLock); if (sr->watchdogLock) {
if (gWatchdogWakeup) { sr->watchdogWakeup = PR_NewCondVar(sr->watchdogLock);
gSleepWakeup = PR_NewCondVar(gWatchdogLock); if (sr->watchdogWakeup) {
if (gSleepWakeup) sr->sleepWakeup = PR_NewCondVar(sr->watchdogLock);
if (sr->sleepWakeup)
return true; return true;
PR_DestroyCondVar(gWatchdogWakeup); PR_DestroyCondVar(sr->watchdogWakeup);
} }
PR_DestroyLock(gWatchdogLock); PR_DestroyLock(sr->watchdogLock);
} }
return false; return false;
} }
static void static void
KillWatchdog() KillWatchdog(JSRuntime* rt)
{ {
ShellRuntime* sr = GetShellRuntime(rt);
PRThread* thread; PRThread* thread;
PR_Lock(gWatchdogLock); PR_Lock(sr->watchdogLock);
thread = gWatchdogThread; thread = sr->watchdogThread;
if (thread) { if (thread) {
/* /*
* The watchdog thread is running, tell it to terminate waking it up * The watchdog thread is running, tell it to terminate waking it up
* if necessary. * if necessary.
*/ */
gWatchdogThread = nullptr; sr->watchdogThread = nullptr;
PR_NotifyCondVar(gWatchdogWakeup); PR_NotifyCondVar(sr->watchdogWakeup);
} }
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
if (thread) if (thread)
PR_JoinThread(thread); PR_JoinThread(thread);
PR_DestroyCondVar(gSleepWakeup); PR_DestroyCondVar(sr->sleepWakeup);
PR_DestroyCondVar(gWatchdogWakeup); PR_DestroyCondVar(sr->watchdogWakeup);
PR_DestroyLock(gWatchdogLock); PR_DestroyLock(sr->watchdogLock);
} }
static void static void
@ -2736,24 +2798,25 @@ WatchdogMain(void* arg)
PR_SetCurrentThreadName("JS Watchdog"); PR_SetCurrentThreadName("JS Watchdog");
JSRuntime* rt = (JSRuntime*) arg; JSRuntime* rt = (JSRuntime*) arg;
ShellRuntime* sr = GetShellRuntime(rt);
PR_Lock(gWatchdogLock); PR_Lock(sr->watchdogLock);
while (gWatchdogThread) { while (sr->watchdogThread) {
int64_t now = PRMJ_Now(); 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 * The timeout has just expired. Request an interrupt callback
* outside the lock. * outside the lock.
*/ */
gWatchdogHasTimeout = false; sr->watchdogHasTimeout = false;
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
CancelExecution(rt); CancelExecution(rt);
PR_Lock(gWatchdogLock); PR_Lock(sr->watchdogLock);
/* Wake up any threads doing sleep. */ /* Wake up any threads doing sleep. */
PR_NotifyAllCondVar(gSleepWakeup); PR_NotifyAllCondVar(sr->sleepWakeup);
} else { } else {
if (gWatchdogHasTimeout) { if (sr->watchdogHasTimeout) {
/* /*
* Time hasn't expired yet. Simulate an interrupt callback * Time hasn't expired yet. Simulate an interrupt callback
* which doesn't abort execution. * which doesn't abort execution.
@ -2762,58 +2825,61 @@ WatchdogMain(void* arg)
} }
uint64_t sleepDuration = PR_INTERVAL_NO_TIMEOUT; uint64_t sleepDuration = PR_INTERVAL_NO_TIMEOUT;
if (gWatchdogHasTimeout) if (sr->watchdogHasTimeout)
sleepDuration = PR_TicksPerSecond() / 10; sleepDuration = PR_TicksPerSecond() / 10;
mozilla::DebugOnly<PRStatus> status = mozilla::DebugOnly<PRStatus> status =
PR_WaitCondVar(gWatchdogWakeup, sleepDuration); PR_WaitCondVar(sr->watchdogWakeup, sleepDuration);
MOZ_ASSERT(status == PR_SUCCESS); MOZ_ASSERT(status == PR_SUCCESS);
} }
} }
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
} }
static bool static bool
ScheduleWatchdog(JSRuntime* rt, double t) ScheduleWatchdog(JSRuntime* rt, double t)
{ {
ShellRuntime* sr = GetShellRuntime(rt);
if (t <= 0) { if (t <= 0) {
PR_Lock(gWatchdogLock); PR_Lock(sr->watchdogLock);
gWatchdogHasTimeout = false; sr->watchdogHasTimeout = false;
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
return true; return true;
} }
int64_t interval = int64_t(ceil(t * PRMJ_USEC_PER_SEC)); int64_t interval = int64_t(ceil(t * PRMJ_USEC_PER_SEC));
int64_t timeout = PRMJ_Now() + interval; int64_t timeout = PRMJ_Now() + interval;
PR_Lock(gWatchdogLock); PR_Lock(sr->watchdogLock);
if (!gWatchdogThread) { if (!sr->watchdogThread) {
MOZ_ASSERT(!gWatchdogHasTimeout); MOZ_ASSERT(!sr->watchdogHasTimeout);
gWatchdogThread = PR_CreateThread(PR_USER_THREAD, sr->watchdogThread = PR_CreateThread(PR_USER_THREAD,
WatchdogMain, WatchdogMain,
rt, rt,
PR_PRIORITY_NORMAL, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, PR_JOINABLE_THREAD,
0); 0);
if (!gWatchdogThread) { if (!sr->watchdogThread) {
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
return false; return false;
} }
} else if (!gWatchdogHasTimeout || IsBefore(timeout, gWatchdogTimeout)) { } else if (!sr->watchdogHasTimeout || IsBefore(timeout, sr->watchdogTimeout)) {
PR_NotifyCondVar(gWatchdogWakeup); PR_NotifyCondVar(sr->watchdogWakeup);
} }
gWatchdogHasTimeout = true; sr->watchdogHasTimeout = true;
gWatchdogTimeout = timeout; sr->watchdogTimeout = timeout;
PR_Unlock(gWatchdogLock); PR_Unlock(sr->watchdogLock);
return true; return true;
} }
static void static void
CancelExecution(JSRuntime* rt) CancelExecution(JSRuntime* rt)
{ {
gServiceInterrupt = true; ShellRuntime* sr = GetShellRuntime(rt);
sr->serviceInterrupt = true;
JS_RequestInterruptCallback(rt); JS_RequestInterruptCallback(rt);
if (!gInterruptFunc.isNull()) { if (!sr->interruptFunc.isNull()) {
static const char msg[] = "Script runs for too long, terminating.\n"; static const char msg[] = "Script runs for too long, terminating.\n";
fputs(msg, stderr); fputs(msg, stderr);
} }
@ -2827,7 +2893,7 @@ SetTimeoutValue(JSContext* cx, double t)
JS_ReportError(cx, "Excessive timeout value"); JS_ReportError(cx, "Excessive timeout value");
return false; return false;
} }
gTimeoutInterval = t; GetShellRuntime(cx)->timeoutInterval = t;
if (!ScheduleWatchdog(cx->runtime(), t)) { if (!ScheduleWatchdog(cx->runtime(), t)) {
JS_ReportError(cx, "Failed to create the watchdog"); JS_ReportError(cx, "Failed to create the watchdog");
return false; return false;
@ -2838,10 +2904,11 @@ SetTimeoutValue(JSContext* cx, double t)
static bool static bool
Timeout(JSContext* cx, unsigned argc, Value* vp) Timeout(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() == 0) { if (args.length() == 0) {
args.rval().setNumber(gTimeoutInterval); args.rval().setNumber(sr->timeoutInterval);
return true; return true;
} }
@ -2860,7 +2927,7 @@ Timeout(JSContext* cx, unsigned argc, Value* vp)
JS_ReportError(cx, "Second argument must be a timeout function"); JS_ReportError(cx, "Second argument must be a timeout function");
return false; return false;
} }
gInterruptFunc = value; sr->interruptFunc = value;
} }
args.rval().setUndefined(); args.rval().setUndefined();
@ -2878,7 +2945,7 @@ InterruptIf(JSContext* cx, unsigned argc, Value* vp)
} }
if (ToBoolean(args[0])) { if (ToBoolean(args[0])) {
gServiceInterrupt = true; GetShellRuntime(cx)->serviceInterrupt = true;
JS_RequestInterruptCallback(cx->runtime()); JS_RequestInterruptCallback(cx->runtime());
} }
@ -2895,7 +2962,7 @@ InvokeInterruptCallbackWrapper(JSContext* cx, unsigned argc, Value* vp)
return false; return false;
} }
gServiceInterrupt = true; GetShellRuntime(cx)->serviceInterrupt = true;
JS_RequestInterruptCallback(cx->runtime()); JS_RequestInterruptCallback(cx->runtime());
bool interruptRv = CheckForInterrupt(cx); bool interruptRv = CheckForInterrupt(cx);
@ -2931,7 +2998,7 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
JS_ReportError(cx, "Argument must be a function"); JS_ReportError(cx, "Argument must be a function");
return false; return false;
} }
gInterruptFunc = value; GetShellRuntime(cx)->interruptFunc = value;
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
@ -2940,10 +3007,11 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
static bool static bool
EnableLastWarning(JSContext* cx, unsigned argc, Value* vp) EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
gLastWarningEnabled = true; sr->lastWarningEnabled = true;
gLastWarning.setNull(); sr->lastWarning.setNull();
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
@ -2952,10 +3020,11 @@ EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
static bool static bool
DisableLastWarning(JSContext* cx, unsigned argc, Value* vp) DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
gLastWarningEnabled = false; sr->lastWarningEnabled = false;
gLastWarning.setNull(); sr->lastWarning.setNull();
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
@ -2964,31 +3033,33 @@ DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
static bool static bool
GetLastWarning(JSContext* cx, unsigned argc, Value* vp) GetLastWarning(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
if (!gLastWarningEnabled) { if (!sr->lastWarningEnabled) {
JS_ReportError(cx, "Call enableLastWarning first."); JS_ReportError(cx, "Call enableLastWarning first.");
return false; return false;
} }
if (!JS_WrapValue(cx, &gLastWarning)) if (!JS_WrapValue(cx, &sr->lastWarning))
return false; return false;
args.rval().set(gLastWarning); args.rval().set(sr->lastWarning);
return true; return true;
} }
static bool static bool
ClearLastWarning(JSContext* cx, unsigned argc, Value* vp) ClearLastWarning(JSContext* cx, unsigned argc, Value* vp)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
if (!gLastWarningEnabled) { if (!sr->lastWarningEnabled) {
JS_ReportError(cx, "Call enableLastWarning first."); JS_ReportError(cx, "Call enableLastWarning first.");
return false; return false;
} }
gLastWarning.setNull(); sr->lastWarning.setNull();
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
@ -3893,6 +3964,11 @@ static bool
SetCachingEnabled(JSContext* cx, unsigned argc, Value* vp) SetCachingEnabled(JSContext* cx, unsigned argc, Value* vp)
{ {
CallArgs args = CallArgsFromVp(argc, 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)); jsCachingEnabled = ToBoolean(args.get(0));
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
@ -5142,7 +5218,7 @@ CreateLastWarningObject(JSContext* cx, JSErrorReport* report)
if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal)) if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal))
return false; return false;
gLastWarning.setObject(*warningObj); GetShellRuntime(cx)->lastWarning.setObject(*warningObj);
return true; return true;
} }
@ -5184,7 +5260,9 @@ PrintStackTrace(JSContext* cx, HandleValue exn)
void void
js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) 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); JS::AutoSaveExceptionState savedExc(cx);
if (!CreateLastWarningObject(cx, report)) { if (!CreateLastWarningObject(cx, report)) {
fputs("Unhandled error happened while creating last warning object.\n", gOutFile); 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)) if (JS_IsExceptionPending(cx))
(void) JS_GetPendingException(cx, &exn); (void) JS_GetPendingException(cx, &exn);
gGotError = PrintError(cx, gErrFile, message, report, reportWarnings); sr->gotError = PrintError(cx, gErrFile, message, report, reportWarnings);
if (!exn.isUndefined()) { if (!exn.isUndefined()) {
JS::AutoSaveExceptionState savedExc(cx); JS::AutoSaveExceptionState savedExc(cx);
if (!PrintStackTrace(cx, exn)) 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->exnType != JSEXN_NONE && !JSREPORT_IS_WARNING(report->flags)) {
if (report->errorNumber == JSMSG_OUT_OF_MEMORY) { if (report->errorNumber == JSMSG_OUT_OF_MEMORY)
gExitCode = EXITCODE_OUT_OF_MEMORY; sr->exitCode = EXITCODE_OUT_OF_MEMORY;
} else { else
gExitCode = EXITCODE_RUNTIME_ERROR; 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 // memory", which may or may not be caught. Otherwise the engine will just
// unwind and return null/false, with no exception set. // unwind and return null/false, with no exception set.
if (!JS_IsRunning(cx)) if (!JS_IsRunning(cx))
gGotError = true; GetShellRuntime(cx)->gotError = true;
} }
static bool static bool
@ -5767,6 +5844,13 @@ NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
return nullptr; return nullptr;
#endif #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 #ifdef JS_HAS_CTYPES
if (!JS_InitCTypesClass(cx, glob)) if (!JS_InitCTypesClass(cx, glob))
return nullptr; return nullptr;
@ -5880,6 +5964,8 @@ OptionFailure(const char* option, const char* str)
static int static int
ProcessArgs(JSContext* cx, OptionParser* op) ProcessArgs(JSContext* cx, OptionParser* op)
{ {
ShellRuntime* sr = GetShellRuntime(cx);
if (op->getBoolOption('s')) if (op->getBoolOption('s'))
JS::RuntimeOptionsRef(cx).toggleExtraWarnings(); JS::RuntimeOptionsRef(cx).toggleExtraWarnings();
@ -5892,7 +5978,7 @@ ProcessArgs(JSContext* cx, OptionParser* op)
if (filePaths.empty() && codeChunks.empty() && !op->getStringArg("script")) { if (filePaths.empty() && codeChunks.empty() && !op->getStringArg("script")) {
Process(cx, nullptr, true); /* Interactive. */ Process(cx, nullptr, true); /* Interactive. */
return gExitCode; return sr->exitCode;
} }
while (!filePaths.empty() || !codeChunks.empty()) { while (!filePaths.empty() || !codeChunks.empty()) {
@ -5901,8 +5987,8 @@ ProcessArgs(JSContext* cx, OptionParser* op)
if (fpArgno < ccArgno) { if (fpArgno < ccArgno) {
char* path = filePaths.front(); char* path = filePaths.front();
Process(cx, path, false); Process(cx, path, false);
if (gExitCode) if (sr->exitCode)
return gExitCode; return sr->exitCode;
filePaths.popFront(); filePaths.popFront();
} else { } else {
const char* code = codeChunks.front(); const char* code = codeChunks.front();
@ -5910,27 +5996,27 @@ ProcessArgs(JSContext* cx, OptionParser* op)
JS::CompileOptions opts(cx); JS::CompileOptions opts(cx);
opts.setFileAndLine("-e", 1); opts.setFileAndLine("-e", 1);
if (!JS::Evaluate(cx, opts, code, strlen(code), &rval)) 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(); codeChunks.popFront();
if (gQuitting) if (sr->quitting)
break; break;
} }
} }
if (gQuitting) if (sr->quitting)
return gExitCode ? gExitCode : EXIT_SUCCESS; return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
/* The |script| argument is processed after all options. */ /* The |script| argument is processed after all options. */
if (const char* path = op->getStringArg("script")) { if (const char* path = op->getStringArg("script")) {
Process(cx, path, false); Process(cx, path, false);
if (gExitCode) if (sr->exitCode)
return gExitCode; return sr->exitCode;
} }
if (op->getBoolOption('i')) if (op->getBoolOption('i'))
Process(cx, nullptr, true); Process(cx, nullptr, true);
return gExitCode ? gExitCode : EXIT_SUCCESS; return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
} }
static bool static bool
@ -6530,13 +6616,18 @@ main(int argc, char** argv, char** envp)
if (!rt) if (!rt)
return 1; return 1;
mozilla::UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>();
if (!sr)
return 1;
JS_SetRuntimePrivate(rt, sr.get());
JS_SetErrorReporter(rt, my_ErrorReporter); JS_SetErrorReporter(rt, my_ErrorReporter);
JS::SetOutOfMemoryCallback(rt, my_OOMCallback, nullptr); JS::SetOutOfMemoryCallback(rt, my_OOMCallback, nullptr);
if (!SetRuntimeOptions(rt, op)) if (!SetRuntimeOptions(rt, op))
return 1; return 1;
gInterruptFunc.init(rt, NullValue()); sr->interruptFunc.init(rt, NullValue());
gLastWarning.init(rt, NullValue()); sr->lastWarning.init(rt, NullValue());
JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff); JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
@ -6594,7 +6685,7 @@ main(int argc, char** argv, char** envp)
DestroyContext(cx, true); DestroyContext(cx, true);
KillWatchdog(); KillWatchdog(rt);
MOZ_ASSERT_IF(!CanUseExtraThreads(), workerThreads.empty()); MOZ_ASSERT_IF(!CanUseExtraThreads(), workerThreads.empty());
for (size_t i = 0; i < workerThreads.length(); i++) for (size_t i = 0; i < workerThreads.length(); i++)

Просмотреть файл

@ -36,11 +36,11 @@ class base {
override() { overrideCalled = "base" } override() { overrideCalled = "base" }
} }
class derived extends base { class derived extends base {
constructor() { }; constructor() { super(); };
override() { overrideCalled = "derived"; } override() { overrideCalled = "derived"; }
} }
var derivedExpr = class extends base { var derivedExpr = class extends base {
constructor() { }; constructor() { super(); };
override() { overrideCalled = "derived"; } override() { overrideCalled = "derived"; }
}; };

Просмотреть файл

@ -18,6 +18,7 @@ class derived extends base {
// Make sure eval and arrows are still valid in non-derived constructors. // Make sure eval and arrows are still valid in non-derived constructors.
new base(); new base();
// Eval throws in derived class constructors, in both class expressions and // Eval throws in derived class constructors, in both class expressions and
// statements. // statements.
assertThrowsInstanceOf((() => new derived()), InternalError); assertThrowsInstanceOf((() => new derived()), InternalError);
@ -26,8 +27,8 @@ assertThrowsInstanceOf((() => new class extends base { constructor() { eval('')
var g = newGlobal(); var g = newGlobal();
var dbg = Debugger(g); var dbg = Debugger(g);
dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); }; dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); };
g.eval("new class foo extends null { constructor() { debugger; } }()");
g.eval("new class foo extends null { constructor() { debugger; return {}; } }()");
`; `;
if (classesEnabled()) if (classesEnabled())

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше