зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-i
This commit is contained in:
Коммит
4457b52a0c
2
CLOBBER
2
CLOBBER
|
@ -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())
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче