зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central r=merge a=merge
This commit is contained in:
Коммит
92d28bd8f2
|
@ -1545,7 +1545,7 @@ AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
|
|||
already_AddRefed<IAccessible>
|
||||
AccessibleWrap::GetRemoteIAccessibleFor(const VARIANT& aVarChild)
|
||||
{
|
||||
DocAccessible* doc = Document();
|
||||
a11y::RootAccessible* root = RootAccessible();
|
||||
const nsTArray<DocAccessibleParent*>* remoteDocs =
|
||||
DocManager::TopLevelRemoteDocs();
|
||||
if (!remoteDocs) {
|
||||
|
@ -1570,7 +1570,7 @@ AccessibleWrap::GetRemoteIAccessibleFor(const VARIANT& aVarChild)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (outerDoc->Document() != doc) {
|
||||
if (outerDoc->RootAccessible() != root) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1042,7 +1042,11 @@ pref("dom.ipc.plugins.sandbox-level.flash", 0);
|
|||
// On windows these levels are:
|
||||
// See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
|
||||
// SetSecurityLevelForContentProcess() for what the different settings mean.
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("security.sandbox.content.level", 5);
|
||||
#else
|
||||
pref("security.sandbox.content.level", 4);
|
||||
#endif
|
||||
|
||||
// This controls the depth of stack trace that is logged when Windows sandbox
|
||||
// logging is turned on. This is only currently available for the content
|
||||
|
|
|
@ -1153,14 +1153,11 @@ nsContextMenu.prototype = {
|
|||
};
|
||||
|
||||
// setting up a new channel for 'right click - save link as ...'
|
||||
// ideally we should use:
|
||||
// * doc - as the loadingNode, and/or
|
||||
// * this.principal - as the loadingPrincipal
|
||||
// for now lets use systemPrincipal to bypass mixedContentBlocker
|
||||
// checks after redirects, see bug: 1136055
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: makeURI(linkURL),
|
||||
loadUsingSystemPrincipal: true
|
||||
loadingPrincipal: this.principal,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD,
|
||||
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
|
||||
});
|
||||
|
||||
if (linkDownload)
|
||||
|
|
|
@ -30,3 +30,7 @@ tags = openwindow
|
|||
[browser_imageCache.js]
|
||||
[browser_count_and_remove.js]
|
||||
[browser_relatedTab.js]
|
||||
[browser_saveLink.js]
|
||||
support-files =
|
||||
saveLink.sjs
|
||||
!/toolkit/content/tests/browser/common/mockTransfer.js
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
"use strict";
|
||||
|
||||
const BASE_ORIGIN = "https://example.com";
|
||||
const URI = BASE_ORIGIN +
|
||||
"/browser/browser/components/contextualidentity/test/browser/saveLink.sjs";
|
||||
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(window);
|
||||
|
||||
add_task(async function setup() {
|
||||
info("Setting the prefs.");
|
||||
|
||||
// make sure userContext is enabled.
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true]
|
||||
]});
|
||||
});
|
||||
|
||||
add_task(async function test() {
|
||||
info("Let's open a new window");
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
info("Opening tab with UCI: 1");
|
||||
let tab = BrowserTestUtils.addTab(win.gBrowser, URI + "?UCI=1", {userContextId: 1});
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
win.gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
info("Waiting to load content");
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(win.document, "popupshown");
|
||||
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#fff", {type: "contextmenu", button: 2},
|
||||
win.gBrowser.selectedBrowser);
|
||||
info("Right clicked!");
|
||||
|
||||
await popupShownPromise;
|
||||
info("Context menu opened");
|
||||
|
||||
info("Let's create a temporary dir");
|
||||
let tempDir = createTemporarySaveDirectory();
|
||||
let destFile;
|
||||
|
||||
MockFilePicker.displayDirectory = tempDir;
|
||||
MockFilePicker.showCallback = fp => {
|
||||
info("MockFilePicker showCallback");
|
||||
|
||||
let fileName = fp.defaultString;
|
||||
destFile = tempDir.clone();
|
||||
destFile.append(fileName);
|
||||
|
||||
MockFilePicker.setFiles([destFile]);
|
||||
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
|
||||
|
||||
info("MockFilePicker showCallback done");
|
||||
};
|
||||
|
||||
let transferCompletePromise = new Promise((resolve) => {
|
||||
function onTransferComplete(downloadSuccess) {
|
||||
ok(downloadSuccess, "File should have been downloaded successfully");
|
||||
resolve();
|
||||
}
|
||||
|
||||
mockTransferCallback = onTransferComplete;
|
||||
mockTransferRegisterer.register();
|
||||
});
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
mockTransferRegisterer.unregister();
|
||||
MockFilePicker.cleanup();
|
||||
tempDir.remove(true);
|
||||
});
|
||||
|
||||
// Select "Save Link As" option from context menu
|
||||
let saveLinkCommand = win.document.getElementById("context-savelink");
|
||||
info("saveLinkCommand: " + saveLinkCommand);
|
||||
saveLinkCommand.doCommand();
|
||||
|
||||
let contextMenu = win.document.getElementById("contentAreaContextMenu");
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
contextMenu.hidePopup();
|
||||
await popupHiddenPromise;
|
||||
info("popup hidden");
|
||||
|
||||
await transferCompletePromise;
|
||||
|
||||
// Let's query the SJS to know if the download happened with the correct cookie.
|
||||
let response = await fetch(URI + "?result=1");
|
||||
let text = await response.text();
|
||||
is(text, "Result:UCI=1", "Correct cookie used: -" + text + "-");
|
||||
|
||||
info("Closing the window");
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
/* import-globals-from ../../../../../toolkit/content/tests/browser/common/mockTransfer.js */
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js", this);
|
||||
|
||||
function createTemporarySaveDirectory() {
|
||||
let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
saveDir.append("testsavedir");
|
||||
if (!saveDir.exists()) {
|
||||
info("create testsavedir!");
|
||||
saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||
}
|
||||
info("return from createTempSaveDir: " + saveDir.path);
|
||||
return saveDir;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
const HTTP_ORIGIN = "http://example.com";
|
||||
const HTTPS_ORIGIN = "https://example.com";
|
||||
const URI_PATH = "/browser/browser/components/contextualidentity/test/browser/saveLink.sjs";
|
||||
|
||||
Components.utils.importGlobalProperties(["URLSearchParams"]);
|
||||
|
||||
function handleRequest(aRequest, aResponse) {
|
||||
var params = new URLSearchParams(aRequest.queryString);
|
||||
|
||||
// This is the first request, where we set the cookie.
|
||||
if (params.has("UCI")) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.setHeader("Set-Cookie", "UCI=" + params.get("UCI"));
|
||||
aResponse.write("<html><body><a href='" + HTTPS_ORIGIN + URI_PATH + "?redirect=1' id='fff'>this is a link</a></body></html>");
|
||||
return;
|
||||
}
|
||||
|
||||
// Second request. This is the save-as content, but we make a redirect to see
|
||||
// if we are able to follow it.
|
||||
if (params.has("redirect")) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 302, "Found");
|
||||
aResponse.setHeader("Location", HTTP_ORIGIN + URI_PATH + "?download=1", false);
|
||||
aResponse.write("Redirect!");
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the 3rd request where we offer the content to be saved.
|
||||
if (params.has("download")) {
|
||||
setState("downloadUCI", aRequest.getHeader("Cookie"));
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.write("All Good!");
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the last request to check that the download happened with the correct cookie
|
||||
if (params.has("result")) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.write("Result:" + getState("downloadUCI"));
|
||||
return;
|
||||
}
|
||||
|
||||
// We should not be here!
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 500);
|
||||
aResponse.write("ERROR!!!");
|
||||
}
|
|
@ -348,7 +348,6 @@ this.TranslationTelemetry = {
|
|||
* recording the automatic rejection of the offer.
|
||||
*/
|
||||
recordAutoRejectedTranslationOffer() {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.AUTO_REJECTED().add();
|
||||
},
|
||||
|
||||
|
@ -362,7 +361,6 @@ this.TranslationTelemetry = {
|
|||
* The number of characters that were translated
|
||||
*/
|
||||
recordTranslation(langFrom, langTo, numCharacters) {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.PAGES().add();
|
||||
this.HISTOGRAMS.PAGES_BY_LANG().add(langFrom + " -> " + langTo);
|
||||
this.HISTOGRAMS.CHARACTERS().add(numCharacters);
|
||||
|
@ -381,7 +379,6 @@ this.TranslationTelemetry = {
|
|||
* be passed.
|
||||
*/
|
||||
recordDetectedLanguageChange(beforeFirstTranslation) {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.DETECTION_CHANGES().add(beforeFirstTranslation);
|
||||
},
|
||||
|
||||
|
@ -391,7 +388,6 @@ this.TranslationTelemetry = {
|
|||
* user changes in the language in the UI.
|
||||
*/
|
||||
recordTargetLanguageChange() {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.TARGET_CHANGES().add();
|
||||
},
|
||||
|
||||
|
@ -399,7 +395,6 @@ this.TranslationTelemetry = {
|
|||
* Record a denied translation offer.
|
||||
*/
|
||||
recordDeniedTranslationOffer() {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.DENIED().add();
|
||||
},
|
||||
|
||||
|
@ -407,7 +402,6 @@ this.TranslationTelemetry = {
|
|||
* Record a "Show Original" command use.
|
||||
*/
|
||||
recordShowOriginalContent() {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.SHOW_ORIGINAL().add();
|
||||
},
|
||||
|
||||
|
@ -415,7 +409,6 @@ this.TranslationTelemetry = {
|
|||
* Record the state of translation preferences.
|
||||
*/
|
||||
recordPreferences() {
|
||||
if (!this._canRecord) return;
|
||||
if (Services.prefs.getBoolPref(TRANSLATION_PREF_SHOWUI)) {
|
||||
this.HISTOGRAMS.SHOW_UI().add(1);
|
||||
}
|
||||
|
@ -425,18 +418,9 @@ this.TranslationTelemetry = {
|
|||
},
|
||||
|
||||
_recordOpportunity(language, success) {
|
||||
if (!this._canRecord) return;
|
||||
this.HISTOGRAMS.OPPORTUNITIES().add(success);
|
||||
this.HISTOGRAMS.OPPORTUNITIES_BY_LANG().add(language, success);
|
||||
},
|
||||
|
||||
/**
|
||||
* A shortcut for reading the telemetry preference.
|
||||
*
|
||||
*/
|
||||
_canRecord() {
|
||||
return Services.prefs.getBoolPref("toolkit.telemetry.enabled");
|
||||
}
|
||||
};
|
||||
|
||||
this.TranslationTelemetry.init();
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"size": 479280,
|
||||
"digest": "dd7e9d67fc858f670502a16266963b15d8fb9a2fa4fc638ba1a27e17318b84ade5a9c1284783905dfbe113ce59690c9232c182e0466d53a37182e8aedea5530f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "breakpad-tools.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 1737944,
|
||||
"visibility": "public",
|
||||
"digest": "76d704f0bfa110f5ea298b87200e34ec09d039b9d1a59ec819fc8e02b2cf073af32a4536dca33a3813f037a557fd0669b48a063c7a920f6308b307148029d41f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "linux64-minidump_stackwalk"
|
||||
}
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
This is the PDF.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 2.0.106
|
||||
Current extension version is: 2.0.120
|
||||
|
||||
Taken from upstream commit: 0052dc2b
|
||||
Taken from upstream commit: e162df59
|
||||
|
|
|
@ -1961,7 +1961,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
|
|||
if (worker.destroyed) {
|
||||
return Promise.reject(new Error('Worker was destroyed'));
|
||||
}
|
||||
let apiVersion = '2.0.106';
|
||||
let apiVersion = '2.0.120';
|
||||
source.disableAutoFetch = (0, _dom_utils.getDefaultSetting)('disableAutoFetch');
|
||||
source.disableStream = (0, _dom_utils.getDefaultSetting)('disableStream');
|
||||
source.chunkedViewerLoading = !!pdfDataRangeTransport;
|
||||
|
@ -3258,8 +3258,8 @@ var InternalRenderTask = function InternalRenderTaskClosure() {
|
|||
}();
|
||||
var version, build;
|
||||
{
|
||||
exports.version = version = '2.0.106';
|
||||
exports.build = build = '0052dc2b';
|
||||
exports.version = version = '2.0.120';
|
||||
exports.build = build = 'e162df59';
|
||||
}
|
||||
exports.getDocument = getDocument;
|
||||
exports.LoopbackPort = LoopbackPort;
|
||||
|
@ -4993,8 +4993,8 @@ exports.SVGGraphics = SVGGraphics;
|
|||
"use strict";
|
||||
|
||||
|
||||
var pdfjsVersion = '2.0.106';
|
||||
var pdfjsBuild = '0052dc2b';
|
||||
var pdfjsVersion = '2.0.120';
|
||||
var pdfjsBuild = 'e162df59';
|
||||
var pdfjsSharedUtil = __w_pdfjs_require__(0);
|
||||
var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
|
||||
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
|
||||
|
@ -8118,8 +8118,8 @@ if (!_global_scope2.default.PDFJS) {
|
|||
}
|
||||
var PDFJS = _global_scope2.default.PDFJS;
|
||||
{
|
||||
PDFJS.version = '2.0.106';
|
||||
PDFJS.build = '0052dc2b';
|
||||
PDFJS.version = '2.0.120';
|
||||
PDFJS.build = 'e162df59';
|
||||
}
|
||||
PDFJS.pdfBug = false;
|
||||
if (PDFJS.verbosity !== undefined) {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -135,7 +135,6 @@ _pdfjsLib.PDFJS.useOnlyCssZoom = _pdfjsLib.PDFJS.useOnlyCssZoom === undefined ?
|
|||
_pdfjsLib.PDFJS.maxCanvasPixels = _pdfjsLib.PDFJS.maxCanvasPixels === undefined ? 16777216 : _pdfjsLib.PDFJS.maxCanvasPixels;
|
||||
_pdfjsLib.PDFJS.disableHistory = _pdfjsLib.PDFJS.disableHistory === undefined ? false : _pdfjsLib.PDFJS.disableHistory;
|
||||
_pdfjsLib.PDFJS.disableTextLayer = _pdfjsLib.PDFJS.disableTextLayer === undefined ? false : _pdfjsLib.PDFJS.disableTextLayer;
|
||||
_pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom = _pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom === undefined ? false : _pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom;
|
||||
;
|
||||
function getOutputScale(ctx) {
|
||||
let devicePixelRatio = window.devicePixelRatio || 1;
|
||||
|
@ -1832,9 +1831,6 @@ function webViewerInitialized() {
|
|||
if ('verbosity' in hashParams) {
|
||||
_pdfjsLib.PDFJS.verbosity = hashParams['verbosity'] | 0;
|
||||
}
|
||||
if ('ignorecurrentpositiononzoom' in hashParams) {
|
||||
_pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom = hashParams['ignorecurrentpositiononzoom'] === 'true';
|
||||
}
|
||||
if ('textlayer' in hashParams) {
|
||||
switch (hashParams['textlayer']) {
|
||||
case 'off':
|
||||
|
@ -5376,7 +5372,19 @@ class PDFThumbnailViewer {
|
|||
if (numVisibleThumbs > 0) {
|
||||
let first = visibleThumbs.first.id;
|
||||
let last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first;
|
||||
let shouldScroll = false;
|
||||
if (page <= first || page >= last) {
|
||||
shouldScroll = true;
|
||||
} else {
|
||||
visibleThumbs.views.some(function (view) {
|
||||
if (view.id !== page) {
|
||||
return false;
|
||||
}
|
||||
shouldScroll = view.percent < 100;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (shouldScroll) {
|
||||
(0, _ui_utils.scrollIntoView)(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
|
||||
}
|
||||
}
|
||||
|
@ -6243,7 +6251,7 @@ class BaseViewer {
|
|||
if (!noScroll) {
|
||||
let page = this._currentPageNumber,
|
||||
dest;
|
||||
if (this._location && !_pdfjsLib.PDFJS.ignoreCurrentPositionOnZoom && !(this.isInPresentationMode || this.isChangingPresentationMode)) {
|
||||
if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) {
|
||||
page = this._location.pageNumber;
|
||||
dest = [null, { name: 'XYZ' }, this._location.left, this._location.top, null];
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ with Files("permissionPrompts/**"):
|
|||
BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
|
||||
|
||||
with Files("preferences/**"):
|
||||
BUG_COMPONENT = ("Firefox", "preferences")
|
||||
BUG_COMPONENT = ("Firefox", "Preferences")
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
# Each test is in it's own directory so it gets run in a clean profile with
|
||||
|
|
|
@ -156,11 +156,31 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
|
|||
AC_DEFINE(MOZ_CLANG_PLUGIN)
|
||||
fi
|
||||
|
||||
if test -n "$ENABLE_MOZSEARCH_PLUGIN"; then
|
||||
if test -z "${ENABLE_CLANG_PLUGIN}"; then
|
||||
AC_MSG_ERROR([Can't use mozsearch plugin without --enable-clang-plugin.])
|
||||
fi
|
||||
|
||||
dnl We use this construct rather than $_objdir to avoid getting /js/src in the
|
||||
dnl path when compiling JS code.
|
||||
OBJDIR="$(dirname $(dirname $(dirname $CLANG_PLUGIN)))"
|
||||
|
||||
CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -add-plugin -Xclang mozsearch-index"
|
||||
|
||||
dnl Parameters are: srcdir, outdir (path where output JSON is stored), objdir.
|
||||
CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -plugin-arg-mozsearch-index -Xclang $_topsrcdir"
|
||||
CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -plugin-arg-mozsearch-index -Xclang $OBJDIR/mozsearch_index"
|
||||
CLANG_PLUGIN_FLAGS="$CLANG_PLUGIN_FLAGS -Xclang -plugin-arg-mozsearch-index -Xclang $OBJDIR"
|
||||
|
||||
AC_DEFINE(MOZ_MOZSEARCH_PLUGIN)
|
||||
fi
|
||||
|
||||
AC_SUBST_LIST(CLANG_PLUGIN_FLAGS)
|
||||
AC_SUBST_LIST(LLVM_CXXFLAGS)
|
||||
AC_SUBST_LIST(LLVM_LDFLAGS)
|
||||
AC_SUBST_LIST(CLANG_LDFLAGS)
|
||||
|
||||
AC_SUBST(ENABLE_CLANG_PLUGIN)
|
||||
AC_SUBST(ENABLE_MOZSEARCH_PLUGIN)
|
||||
|
||||
])
|
||||
|
|
|
@ -41,6 +41,14 @@ UNIFIED_SOURCES += [
|
|||
'VariableUsageHelpers.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['ENABLE_MOZSEARCH_PLUGIN']:
|
||||
UNIFIED_SOURCES += [
|
||||
'mozsearch-plugin/FileOperations.cpp',
|
||||
'mozsearch-plugin/JSONFormatter.cpp',
|
||||
'mozsearch-plugin/MozsearchIndexer.cpp',
|
||||
'mozsearch-plugin/StringOperations.cpp',
|
||||
]
|
||||
|
||||
GENERATED_FILES += ['ThirdPartyPaths.cpp']
|
||||
third_party_paths = GENERATED_FILES['ThirdPartyPaths.cpp']
|
||||
third_party_paths.script = "ThirdPartyPaths.py:generate"
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileOperations.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Make sure that all directories on path exist, excluding the final element of
|
||||
// the path.
|
||||
void ensurePath(std::string Path) {
|
||||
size_t Pos = 0;
|
||||
if (Path[0] == '/') {
|
||||
Pos++;
|
||||
}
|
||||
|
||||
while ((Pos = Path.find('/', Pos)) != std::string::npos) {
|
||||
std::string Portion = Path.substr(0, Pos);
|
||||
if (!Portion.empty()) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int Err = _mkdir(Portion.c_str());
|
||||
#else
|
||||
int Err = mkdir(Portion.c_str(), 0775);
|
||||
#endif
|
||||
if (Err == -1 && errno != EEXIST) {
|
||||
perror("mkdir failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Pos++;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
AutoLockFile::AutoLockFile(const std::string &Filename) {
|
||||
std::string Hash = Hash(filename);
|
||||
std::string MutexName = std::string("Local\\searchfox-") + Hash;
|
||||
std::wstring WideMutexName;
|
||||
WideMutexName.assign(MutexName.begin(), MutexName.end());
|
||||
Handle = CreateMutex(nullptr, false, WideMutexName.c_str());
|
||||
if (Handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
WaitForSingleObject(Handle, INFINITE);
|
||||
|
||||
FileDescriptor = _open(Filename.c_str(), _O_RDWR | _O_CREAT, 0666);
|
||||
}
|
||||
|
||||
AutoLockFile::~AutoLockFile() {
|
||||
_close(FileDescriptor);
|
||||
|
||||
ReleaseMutex(Handle);
|
||||
CloseHandle(Handle);
|
||||
}
|
||||
|
||||
bool AutoLockFile::success() {
|
||||
return Handle != NULL && FileDescriptor != -1;
|
||||
}
|
||||
|
||||
FILE *AutoLockFile::openFile(const char *Mode) {
|
||||
_lseek(FileDescriptor, 0, SEEK_SET);
|
||||
return _fdopen(_dup(FileDescriptor), Mode);
|
||||
}
|
||||
|
||||
bool AutoLockFile::truncateFile(size_t Length) {
|
||||
return _chsize(FileDescriptor, Length) == 0;
|
||||
}
|
||||
|
||||
std::string getAbsolutePath(const std::string &Filename) {
|
||||
char full[_MAX_PATH];
|
||||
if (!_fullpath(Full, Filename.c_str(), _MAX_PATH)) {
|
||||
return std::string("");
|
||||
}
|
||||
return std::string(Full);
|
||||
}
|
||||
#else
|
||||
AutoLockFile::AutoLockFile(const std::string &Filename) {
|
||||
FileDescriptor = open(Filename.c_str(), O_RDWR | O_CREAT, 0666);
|
||||
if (FileDescriptor == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
int rv = flock(FileDescriptor, LOCK_EX);
|
||||
if (rv == 0) {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
AutoLockFile::~AutoLockFile() { close(FileDescriptor); }
|
||||
|
||||
bool AutoLockFile::success() { return FileDescriptor != -1; }
|
||||
|
||||
FILE *AutoLockFile::openFile(const char *Mode) {
|
||||
lseek(FileDescriptor, 0, SEEK_SET);
|
||||
return fdopen(dup(FileDescriptor), Mode);
|
||||
}
|
||||
|
||||
bool AutoLockFile::truncateFile(size_t Length) {
|
||||
return ftruncate(FileDescriptor, Length) == 0;
|
||||
}
|
||||
|
||||
std::string getAbsolutePath(const std::string &Filename) {
|
||||
char Full[4096];
|
||||
if (!realpath(Filename.c_str(), Full)) {
|
||||
return std::string("");
|
||||
}
|
||||
return std::string(Full);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef FileOperations_h
|
||||
#define FileOperations_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Make sure that all directories on path exist, excluding the final element of
|
||||
// the path.
|
||||
void ensurePath(std::string Path);
|
||||
|
||||
std::string getAbsolutePath(const std::string &Filename);
|
||||
|
||||
// Lock the given filename so that it cannot be opened by anyone else until this
|
||||
// object goes out of scope. On Windows, we use a named mutex. On POSIX
|
||||
// platforms, we use flock.
|
||||
struct AutoLockFile {
|
||||
int FileDescriptor = -1;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE Handle = NULL;
|
||||
#endif
|
||||
|
||||
AutoLockFile(const std::string &Filename);
|
||||
~AutoLockFile();
|
||||
|
||||
bool success();
|
||||
|
||||
FILE *openFile(const char *Mode);
|
||||
bool truncateFile(size_t Length);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "JSONFormatter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string.h>
|
||||
|
||||
static std::string replaceAll(std::string Mangled, std::string Pattern,
|
||||
std::string Replacement) {
|
||||
size_t Pos = 0;
|
||||
while ((Pos = Mangled.find(Pattern, Pos)) != std::string::npos) {
|
||||
Mangled = Mangled.replace(Pos, Pattern.length(), Replacement);
|
||||
Pos += Replacement.length();
|
||||
}
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hacky escaping logic with the goal of not upsetting the much more thorough
|
||||
* rust JSON parsing library that actually understands UTF-8. Double-quote
|
||||
* and (escaping) backslash are escaped, as is tab (\t), with newlines (\r\n
|
||||
* and \n) normalized to escaped \n.
|
||||
*
|
||||
* Additionally, everything that's not printable ASCII is simply erased. The
|
||||
* motivating file is media/openmax_il/il112/OMX_Other.h#93 which has a
|
||||
* corrupted apostrophe as <92> in there. The better course of action would
|
||||
* be a validating UTF-8 parse that discards corrupt/non-printable characters.
|
||||
* Since this is motivated by a commenting proof-of-concept and builds are
|
||||
* already slow, I'm punting on that.
|
||||
*/
|
||||
std::string JSONFormatter::escape(std::string Input) {
|
||||
bool NeedsEscape = false;
|
||||
for (char C : Input) {
|
||||
if (C == '\\' || C == '"' || C < 32 || C > 126) {
|
||||
NeedsEscape = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NeedsEscape) {
|
||||
return Input;
|
||||
}
|
||||
|
||||
std::string Cur = Input;
|
||||
Cur = replaceAll(Cur, "\\", "\\\\");
|
||||
Cur = replaceAll(Cur, "\"", "\\\"");
|
||||
Cur = replaceAll(Cur, "\t", "\\t");
|
||||
Cur = replaceAll(Cur, "\r\n", "\\n");
|
||||
Cur = replaceAll(Cur, "\n", "\\n");
|
||||
Cur.erase(std::remove_if(Cur.begin(), Cur.end(),
|
||||
[](char C){ return C < 32 || C > 126; }),
|
||||
Cur.end());
|
||||
return Cur;
|
||||
}
|
||||
|
||||
void JSONFormatter::add(const char *Name, const char *Value) {
|
||||
assert(PropertyCount < kMaxProperties);
|
||||
Properties[PropertyCount] = Property(Name, std::string(Value));
|
||||
PropertyCount++;
|
||||
|
||||
// `"Name":"Value",`
|
||||
Length += strlen(Name) + 3 + strlen(Value) + 2 + 1;
|
||||
}
|
||||
|
||||
void JSONFormatter::add(const char *Name, std::string Value) {
|
||||
std::string Escaped = escape(std::move(Value));
|
||||
|
||||
// `"Name":"Escaped",`
|
||||
Length += strlen(Name) + 3 + Escaped.length() + 2 + 1;
|
||||
|
||||
assert(PropertyCount < kMaxProperties);
|
||||
Properties[PropertyCount] = Property(Name, std::move(Escaped));
|
||||
PropertyCount++;
|
||||
}
|
||||
|
||||
void JSONFormatter::add(const char *Name, int Value) {
|
||||
// 1 digit
|
||||
assert(Value >= 0 && Value < 10);
|
||||
|
||||
assert(PropertyCount < kMaxProperties);
|
||||
Properties[PropertyCount] = Property(Name, Value);
|
||||
PropertyCount++;
|
||||
|
||||
// `"Name":V,`
|
||||
Length += strlen(Name) + 3 + 2;
|
||||
}
|
||||
|
||||
void JSONFormatter::format(std::string &Result) {
|
||||
Result.reserve(Length + 2);
|
||||
|
||||
Result.push_back('{');
|
||||
for (int I = 0; I < PropertyCount; I++) {
|
||||
Result.push_back('"');
|
||||
Result.append(Properties[I].Name);
|
||||
Result.push_back('"');
|
||||
Result.push_back(':');
|
||||
|
||||
if (Properties[I].IsString) {
|
||||
Result.push_back('"');
|
||||
Result.append(Properties[I].StringValue);
|
||||
Result.push_back('"');
|
||||
} else {
|
||||
Result.push_back(Properties[I].IntValue + '0');
|
||||
}
|
||||
|
||||
if (I + 1 != PropertyCount) {
|
||||
Result.push_back(',');
|
||||
}
|
||||
}
|
||||
|
||||
Result.push_back('}');
|
||||
Result.push_back('\n');
|
||||
|
||||
assert(Result.length() == Length + 2);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef JSONFormatter_h
|
||||
#define JSONFormatter_h
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// A very basic JSON formatter that records key/value pairs and outputs a JSON
|
||||
// object that contains only non-object data.
|
||||
class JSONFormatter {
|
||||
// Of these fields, only mEscapedStringValue is owned by this class. All the
|
||||
// others are expected to outlive the class (which is typically allocated
|
||||
// on-stack).
|
||||
struct Property {
|
||||
const char *Name;
|
||||
std::string StringValue;
|
||||
int IntValue;
|
||||
bool IsString;
|
||||
|
||||
Property() {}
|
||||
|
||||
Property(const char* Name, std::string String)
|
||||
: Name(Name), StringValue(std::move(String)), IsString(true) {}
|
||||
|
||||
Property(const char* Name, int Int)
|
||||
: Name(Name), IntValue(Int), IsString(false) {}
|
||||
};
|
||||
|
||||
static const int kMaxProperties = 32;
|
||||
|
||||
Property Properties[kMaxProperties];
|
||||
int PropertyCount;
|
||||
|
||||
// Length of the generated JSON output.
|
||||
size_t Length;
|
||||
|
||||
std::string escape(std::string Input);
|
||||
|
||||
public:
|
||||
JSONFormatter() : PropertyCount(0), Length(0) {}
|
||||
|
||||
void add(const char *Name, const char *Value);
|
||||
void add(const char *Name, std::string Value);
|
||||
void add(const char *Name, int Value);
|
||||
|
||||
void format(std::string &Result);
|
||||
};
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,12 @@
|
|||
This clang plugin code generates a JSON file for each compiler input
|
||||
file. The JSON file contains information about the C++ symbols that
|
||||
are referenced by the input file. The data is eventually consumed by
|
||||
Searchfox. See https://github.com/bill-mccloskey/mozsearch for more
|
||||
information.
|
||||
|
||||
This plugin is enabled with the --enable-clang-plugin and
|
||||
--enable-mozsearch-plugin mozconfig options. The output of the plugin
|
||||
is stored in $OBJDIR/mozsearch_index.
|
||||
|
||||
This code is not a checker, unlike other parts of the Mozilla clang
|
||||
plugin. It cannot be used with clang-tidy.
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "StringOperations.h"
|
||||
|
||||
static unsigned long djbHash(const char *Str) {
|
||||
unsigned long Hash = 5381;
|
||||
|
||||
for (const char *P = Str; *P; P++) {
|
||||
// Hash * 33 + c
|
||||
Hash = ((Hash << 5) + Hash) + *P;
|
||||
}
|
||||
|
||||
return Hash;
|
||||
}
|
||||
|
||||
// This doesn't actually return a hex string of |hash|, but it
|
||||
// does... something. It doesn't really matter what.
|
||||
static void hashToString(unsigned long Hash, char *Buffer) {
|
||||
const char Table[] = {"0123456789abcdef"};
|
||||
char *P = Buffer;
|
||||
while (Hash) {
|
||||
*P = Table[Hash & 0xf];
|
||||
Hash >>= 4;
|
||||
P++;
|
||||
}
|
||||
|
||||
*P = 0;
|
||||
}
|
||||
|
||||
std::string hash(const std::string &Str) {
|
||||
static char HashStr[41];
|
||||
unsigned long H = djbHash(Str.c_str());
|
||||
hashToString(H, HashStr);
|
||||
return std::string(HashStr);
|
||||
}
|
||||
|
||||
std::string toString(int N) {
|
||||
return stringFormat("%d", N);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef StringOperations_h
|
||||
#define StringOperations_h
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
std::string hash(const std::string &Str);
|
||||
|
||||
template <typename... Args>
|
||||
inline std::string stringFormat(const std::string &Format, Args... ArgList) {
|
||||
size_t Len = snprintf(nullptr, 0, Format.c_str(), ArgList...);
|
||||
std::unique_ptr<char[]> Buf(new char[Len + 1]);
|
||||
snprintf(Buf.get(), Len + 1, Format.c_str(), ArgList...);
|
||||
return std::string(Buf.get(), Buf.get() + Len);
|
||||
}
|
||||
|
||||
std::string toString(int N);
|
||||
|
||||
#endif
|
|
@ -1514,6 +1514,12 @@ js_option('--enable-clang-plugin', env='ENABLE_CLANG_PLUGIN',
|
|||
add_old_configure_assignment('ENABLE_CLANG_PLUGIN',
|
||||
depends_if('--enable-clang-plugin')(lambda _: True))
|
||||
|
||||
js_option('--enable-mozsearch-plugin', env='ENABLE_MOZSEARCH_PLUGIN',
|
||||
help="Enable building with the mozsearch indexer plugin")
|
||||
|
||||
add_old_configure_assignment('ENABLE_MOZSEARCH_PLUGIN',
|
||||
depends_if('--enable-mozsearch-plugin')(lambda _: True))
|
||||
|
||||
# Code Coverage
|
||||
# ==============================================================
|
||||
|
||||
|
|
|
@ -19,9 +19,6 @@ add_old_configure_assignment(
|
|||
# lots of useful warnings
|
||||
add_gcc_warning('-Wall')
|
||||
|
||||
# catches C++ version forward-compat issues
|
||||
add_gcc_warning('-Wc++11-compat', cxx_compiler)
|
||||
|
||||
# catches bugs, e.g. "if (c); foo();", few false positives
|
||||
add_gcc_warning('-Wempty-body')
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ with Files('css-properties.js'):
|
|||
BUG_COMPONENT = ('Firefox', 'Developer Tools: CSS Rules Inspector')
|
||||
|
||||
with Files('csscoverage.js'):
|
||||
BUG_COMPONENT = ('Firefox', 'Graphics Commandline and Toolbar')
|
||||
BUG_COMPONENT = ('Firefox', 'Developer Tools: Graphics Commandline and Toolbar')
|
||||
|
||||
with Files('inspector.js'):
|
||||
BUG_COMPONENT = ('Firefox', 'Developer Tools: Inspector')
|
||||
|
|
|
@ -38,8 +38,6 @@ CustomElementCallback::Call()
|
|||
nsIDocument* document = mThisObject->GetComposedDoc();
|
||||
if (document) {
|
||||
NodeInfo* ni = mThisObject->NodeInfo();
|
||||
nsDependentAtomString extType(mOwnerData->mType);
|
||||
|
||||
// We need to do this because at this point, CustomElementDefinition is
|
||||
// not set to CustomElementData yet, so EnqueueLifecycleCallback will
|
||||
// fail to find the CE definition for this custom element.
|
||||
|
@ -47,7 +45,7 @@ CustomElementCallback::Call()
|
|||
CustomElementDefinition* definition =
|
||||
nsContentUtils::LookupCustomElementDefinition(document,
|
||||
ni->LocalName(), ni->NamespaceID(),
|
||||
extType.IsEmpty() ? nullptr : &extType);
|
||||
mOwnerData->GetCustomElementType());
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(
|
||||
nsIDocument::eConnected, mThisObject, nullptr, nullptr, definition);
|
||||
|
@ -132,10 +130,10 @@ CustomElementData::CustomElementData(nsAtom* aType)
|
|||
}
|
||||
|
||||
CustomElementData::CustomElementData(nsAtom* aType, State aState)
|
||||
: mType(aType)
|
||||
, mElementIsBeingCreated(false)
|
||||
: mElementIsBeingCreated(false)
|
||||
, mCreatedCallbackInvoked(true)
|
||||
, mState(aState)
|
||||
, mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -158,6 +156,12 @@ CustomElementData::GetCustomElementDefinition()
|
|||
return mCustomElementDefinition;
|
||||
}
|
||||
|
||||
nsAtom*
|
||||
CustomElementData::GetCustomElementType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementData::Traverse(nsCycleCollectionTraversalCallback& aCb) const
|
||||
{
|
||||
|
@ -269,12 +273,10 @@ CustomElementRegistry::~CustomElementRegistry()
|
|||
|
||||
CustomElementDefinition*
|
||||
CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName,
|
||||
const nsAString* aIs) const
|
||||
nsAtom* aTypeAtom) const
|
||||
{
|
||||
RefPtr<nsAtom> localNameAtom = NS_Atomize(aLocalName);
|
||||
RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom;
|
||||
|
||||
CustomElementDefinition* data = mCustomDefinitions.GetWeak(typeAtom);
|
||||
CustomElementDefinition* data = mCustomDefinitions.GetWeak(aTypeAtom);
|
||||
if (data && data->mLocalName == localNameAtom) {
|
||||
return data;
|
||||
}
|
||||
|
@ -323,47 +325,21 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsAtom* aTyp
|
|||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::SetupCustomElement(Element* aElement,
|
||||
const nsAString* aTypeExtension)
|
||||
CustomElementRegistry::UnregisterUnresolvedElement(Element* aElement,
|
||||
nsAtom* aTypeName)
|
||||
{
|
||||
RefPtr<nsAtom> tagAtom = aElement->NodeInfo()->NameAtom();
|
||||
RefPtr<nsAtom> typeAtom = aTypeExtension ?
|
||||
NS_Atomize(*aTypeExtension) : tagAtom;
|
||||
|
||||
if (aTypeExtension && !aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) {
|
||||
// Custom element setup in the parser happens after the "is"
|
||||
// attribute is added.
|
||||
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
|
||||
nsTArray<nsWeakPtr>* candidates;
|
||||
if (mCandidatesMap.Get(aTypeName, &candidates)) {
|
||||
MOZ_ASSERT(candidates);
|
||||
// We don't need to iterate the candidates array and remove the element from
|
||||
// the array for performance reason. It'll be handled by bug 1396620.
|
||||
for (size_t i = 0; i < candidates->Length(); ++i) {
|
||||
nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
|
||||
if (elem && elem.get() == aElement) {
|
||||
candidates->RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetupCustomElement() should be called with an element that don't have
|
||||
// CustomElementData setup, if not we will hit the assertion in
|
||||
// SetCustomElementData().
|
||||
aElement->SetCustomElementData(new CustomElementData(typeAtom));
|
||||
|
||||
CustomElementDefinition* definition = LookupCustomElementDefinition(
|
||||
aElement->NodeInfo()->LocalName(), aTypeExtension);
|
||||
|
||||
if (!definition) {
|
||||
// The type extension doesn't exist in the registry,
|
||||
// thus we don't need to enqueue callback or adjust
|
||||
// the "is" attribute, but it is possibly an upgrade candidate.
|
||||
RegisterUnresolvedElement(aElement, typeAtom);
|
||||
return;
|
||||
}
|
||||
|
||||
if (definition->mLocalName != tagAtom) {
|
||||
// The element doesn't match the local name for the
|
||||
// definition, thus the element isn't a custom element
|
||||
// and we don't need to do anything more.
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueuing the created callback will set the CustomElementData on the
|
||||
// element, causing prototype swizzling to occur in Element::WrapObject.
|
||||
// We make it synchronously for createElement/createElementNS in order to
|
||||
// pass tests. It'll be removed when we deprecate custom elements v0.
|
||||
SyncInvokeReactions(nsIDocument::eCreated, aElement, definition);
|
||||
}
|
||||
|
||||
/* static */ UniquePtr<CustomElementCallback>
|
||||
|
|
|
@ -114,9 +114,7 @@ struct CustomElementData
|
|||
|
||||
explicit CustomElementData(nsAtom* aType);
|
||||
CustomElementData(nsAtom* aType, State aState);
|
||||
// Custom element type, for <button is="x-button"> or <x-button>
|
||||
// this would be x-button.
|
||||
RefPtr<nsAtom> mType;
|
||||
|
||||
// Element is being created flag as described in the custom elements spec.
|
||||
bool mElementIsBeingCreated;
|
||||
// Flag to determine if the created callback has been invoked, thus it
|
||||
|
@ -134,6 +132,7 @@ struct CustomElementData
|
|||
|
||||
void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
|
||||
CustomElementDefinition* GetCustomElementDefinition();
|
||||
nsAtom* GetCustomElementType();
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
|
||||
void Unlink();
|
||||
|
@ -141,6 +140,9 @@ struct CustomElementData
|
|||
private:
|
||||
virtual ~CustomElementData() {}
|
||||
|
||||
// Custom element type, for <button is="x-button"> or <x-button>
|
||||
// this would be x-button.
|
||||
RefPtr<nsAtom> mType;
|
||||
RefPtr<CustomElementDefinition> mCustomElementDefinition;
|
||||
};
|
||||
|
||||
|
@ -369,18 +371,11 @@ public:
|
|||
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition
|
||||
*/
|
||||
CustomElementDefinition* LookupCustomElementDefinition(
|
||||
const nsAString& aLocalName, const nsAString* aIs = nullptr) const;
|
||||
const nsAString& aLocalName, nsAtom* aTypeAtom) const;
|
||||
|
||||
CustomElementDefinition* LookupCustomElementDefinition(
|
||||
JSContext* aCx, JSObject *aConstructor) const;
|
||||
|
||||
/**
|
||||
* Enqueue created callback or register upgrade candidate for
|
||||
* newly created custom elements, possibly extending an existing type.
|
||||
* ex. <x-button>, <button is="x-button> (type extension)
|
||||
*/
|
||||
void SetupCustomElement(Element* aElement, const nsAString* aTypeExtension);
|
||||
|
||||
static void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
||||
Element* aCustomElement,
|
||||
LifecycleCallbackArgs* aArgs,
|
||||
|
@ -400,15 +395,6 @@ public:
|
|||
*/
|
||||
static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~CustomElementRegistry();
|
||||
|
||||
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
|
||||
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
|
||||
LifecycleCallbackArgs* aArgs,
|
||||
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||
CustomElementDefinition* aDefinition);
|
||||
|
||||
/**
|
||||
* Registers an unresolved custom element that is a candidate for
|
||||
* upgrade when the definition is registered via registerElement.
|
||||
|
@ -420,6 +406,21 @@ private:
|
|||
void RegisterUnresolvedElement(Element* aElement,
|
||||
nsAtom* aTypeName = nullptr);
|
||||
|
||||
/**
|
||||
* Unregister an unresolved custom element that is a candidate for
|
||||
* upgrade when a custom element is removed from tree.
|
||||
*/
|
||||
void UnregisterUnresolvedElement(Element* aElement,
|
||||
nsAtom* aTypeName = nullptr);
|
||||
private:
|
||||
~CustomElementRegistry();
|
||||
|
||||
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
|
||||
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
|
||||
LifecycleCallbackArgs* aArgs,
|
||||
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||
CustomElementDefinition* aDefinition);
|
||||
|
||||
void UpgradeCandidates(nsAtom* aKey,
|
||||
CustomElementDefinition* aDefinition,
|
||||
ErrorResult& aRv);
|
||||
|
|
|
@ -524,7 +524,7 @@ Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
if (data) {
|
||||
// If this is a registered custom element then fix the prototype.
|
||||
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
|
||||
data->mType, &customProto);
|
||||
data->GetCustomElementType(), &customProto);
|
||||
if (customProto &&
|
||||
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
|
||||
// Just go ahead and create with the right proto up front. Set
|
||||
|
@ -1758,8 +1758,14 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
if (CustomElementRegistry::IsCustomElementEnabled() && IsInComposedDoc()) {
|
||||
// Connected callback must be enqueued whenever a custom element becomes
|
||||
// connected.
|
||||
if (GetCustomElementData()) {
|
||||
nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this);
|
||||
CustomElementData* data = GetCustomElementData();
|
||||
if (data) {
|
||||
if (data->mState == CustomElementData::State::eCustom) {
|
||||
nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, this);
|
||||
} else {
|
||||
// Step 7.7.2.2 https://dom.spec.whatwg.org/#concept-node-insert
|
||||
nsContentUtils::TryToUpgradeElement(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2085,10 +2091,19 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
|
||||
// Disconnected must be enqueued whenever a connected custom element becomes
|
||||
// disconnected.
|
||||
if (CustomElementRegistry::IsCustomElementEnabled() &&
|
||||
GetCustomElementData()) {
|
||||
nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eDisconnected,
|
||||
this);
|
||||
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||
CustomElementData* data = GetCustomElementData();
|
||||
if (data) {
|
||||
if (data->mState == CustomElementData::State::eCustom) {
|
||||
nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eDisconnected,
|
||||
this);
|
||||
} else {
|
||||
// Remove an unresolved custom element that is a candidate for
|
||||
// upgrade when a custom element is disconnected.
|
||||
// We will make sure it's shadow-including tree order in bug 1326028.
|
||||
nsContentUtils::UnregisterUnresolvedElement(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2768,8 +2783,11 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
if (CustomElementData* data = GetCustomElementData()) {
|
||||
if (CustomElementDefinition* definition =
|
||||
nsContentUtils::GetElementDefinitionIfObservingAttr(this,
|
||||
data->mType,
|
||||
data->GetCustomElementType(),
|
||||
aName)) {
|
||||
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
|
||||
"AttributeChanged callback should fire only if "
|
||||
"custom element state is custom");
|
||||
RefPtr<nsAtom> oldValueAtom;
|
||||
if (oldValue) {
|
||||
oldValueAtom = oldValue->GetAsAtom();
|
||||
|
@ -3072,8 +3090,11 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
|||
if (CustomElementData* data = GetCustomElementData()) {
|
||||
if (CustomElementDefinition* definition =
|
||||
nsContentUtils::GetElementDefinitionIfObservingAttr(this,
|
||||
data->mType,
|
||||
data->GetCustomElementType(),
|
||||
aName)) {
|
||||
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
|
||||
"AttributeChanged callback should fire only if "
|
||||
"custom element state is custom");
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ NS_CP_ContentTypeName(uint32_t contentType)
|
|||
CASE_RETURN( TYPE_FETCH );
|
||||
CASE_RETURN( TYPE_IMAGESET );
|
||||
CASE_RETURN( TYPE_WEB_MANIFEST );
|
||||
CASE_RETURN( TYPE_SAVEAS_DOWNLOAD );
|
||||
CASE_RETURN( TYPE_INTERNAL_SCRIPT );
|
||||
CASE_RETURN( TYPE_INTERNAL_WORKER );
|
||||
CASE_RETURN( TYPE_INTERNAL_SHARED_WORKER );
|
||||
|
|
|
@ -240,6 +240,7 @@ extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
|
|||
int ns_aware, const char** colon);
|
||||
|
||||
class imgLoader;
|
||||
class nsAtom;
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
@ -10119,11 +10120,32 @@ nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::TryToUpgradeElement(Element* aElement)
|
||||
{
|
||||
NodeInfo* nodeInfo = aElement->NodeInfo();
|
||||
RefPtr<nsAtom> typeAtom =
|
||||
aElement->GetCustomElementData()->GetCustomElementType();
|
||||
CustomElementDefinition* definition =
|
||||
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
|
||||
nodeInfo->LocalName(),
|
||||
nodeInfo->NamespaceID(),
|
||||
typeAtom);
|
||||
if (definition) {
|
||||
nsContentUtils::EnqueueUpgradeReaction(aElement, definition);
|
||||
} else {
|
||||
// Add an unresolved custom element that is a candidate for
|
||||
// upgrade when a custom element is connected to the document.
|
||||
// We will make sure it's shadow-including tree order in bug 1326028.
|
||||
nsContentUtils::RegisterUnresolvedElement(aElement, typeAtom);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ CustomElementDefinition*
|
||||
nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
|
||||
const nsAString& aLocalName,
|
||||
uint32_t aNameSpaceID,
|
||||
const nsAString* aIs)
|
||||
nsAtom* aTypeAtom)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
|
||||
|
@ -10142,27 +10164,16 @@ nsContentUtils::LookupCustomElementDefinition(nsIDocument* aDoc,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return registry->LookupCustomElementDefinition(aLocalName, aIs);
|
||||
return registry->LookupCustomElementDefinition(aLocalName, aTypeAtom);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::SetupCustomElement(Element* aElement,
|
||||
const nsAString* aTypeExtension)
|
||||
nsContentUtils::RegisterUnresolvedElement(Element* aElement, nsAtom* aTypeName)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = aElement->OwnerDoc();
|
||||
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aElement->GetNameSpaceID() != kNameSpaceID_XHTML ||
|
||||
!doc->GetDocShell()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
|
||||
nsIDocument* doc = aElement->OwnerDoc();
|
||||
nsPIDOMWindowInner* window(doc->GetInnerWindow());
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
@ -10172,7 +10183,28 @@ nsContentUtils::SetupCustomElement(Element* aElement,
|
|||
return;
|
||||
}
|
||||
|
||||
return registry->SetupCustomElement(aElement, aTypeExtension);
|
||||
registry->RegisterUnresolvedElement(aElement, aTypeName);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::UnregisterUnresolvedElement(Element* aElement)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
|
||||
RefPtr<nsAtom> typeAtom =
|
||||
aElement->GetCustomElementData()->GetCustomElementType();
|
||||
nsIDocument* doc = aElement->OwnerDoc();
|
||||
nsPIDOMWindowInner* window(doc->GetInnerWindow());
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CustomElementRegistry> registry(window->CustomElements());
|
||||
if (!registry) {
|
||||
return;
|
||||
}
|
||||
|
||||
registry->UnregisterUnresolvedElement(aElement, typeAtom);
|
||||
}
|
||||
|
||||
/* static */ CustomElementDefinition*
|
||||
|
|
|
@ -3029,6 +3029,12 @@ public:
|
|||
*/
|
||||
static bool HttpsStateIsModern(nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Try to upgrade an element.
|
||||
* https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade
|
||||
*/
|
||||
static void TryToUpgradeElement(Element* aElement);
|
||||
|
||||
/**
|
||||
* Looking up a custom element definition.
|
||||
* https://html.spec.whatwg.org/#look-up-a-custom-element-definition
|
||||
|
@ -3037,10 +3043,10 @@ public:
|
|||
LookupCustomElementDefinition(nsIDocument* aDoc,
|
||||
const nsAString& aLocalName,
|
||||
uint32_t aNameSpaceID,
|
||||
const nsAString* aIs = nullptr);
|
||||
nsAtom* aTypeAtom);
|
||||
|
||||
static void SetupCustomElement(Element* aElement,
|
||||
const nsAString* aTypeExtension = nullptr);
|
||||
static void RegisterUnresolvedElement(Element* aElement, nsAtom* aTypeName);
|
||||
static void UnregisterUnresolvedElement(Element* aElement);
|
||||
|
||||
static mozilla::dom::CustomElementDefinition*
|
||||
GetElementDefinitionIfObservingAttr(Element* aCustomElement,
|
||||
|
|
|
@ -181,6 +181,11 @@ interface nsIContentPolicy : nsISupports
|
|||
*/
|
||||
const nsContentPolicyType TYPE_WEB_MANIFEST = 22;
|
||||
|
||||
/**
|
||||
* Indicates an save-as link download from the front-end code.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_SAVEAS_DOWNLOAD = 43;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for scripts loaded through script
|
||||
* elements.
|
||||
|
|
|
@ -463,37 +463,31 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled() && clone->IsElement()) {
|
||||
if (CustomElementRegistry::IsCustomElementEnabled() &&
|
||||
clone->IsHTMLElement()) {
|
||||
// The cloned node may be a custom element that may require
|
||||
// enqueing upgrade reaction.
|
||||
Element* elem = clone->AsElement();
|
||||
CustomElementDefinition* definition = nullptr;
|
||||
Element* cloneElem = clone->AsElement();
|
||||
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
|
||||
if (nsContentUtils::IsCustomElementName(tagAtom)) {
|
||||
definition =
|
||||
CustomElementData* data = elem->GetCustomElementData();
|
||||
|
||||
// Check if node may be custom element by type extension.
|
||||
// ex. <button is="x-button">
|
||||
nsAutoString extension;
|
||||
if (!data || data->GetCustomElementType() != tagAtom) {
|
||||
cloneElem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension);
|
||||
}
|
||||
|
||||
if (data || !extension.IsEmpty()) {
|
||||
RefPtr<nsAtom> typeAtom = extension.IsEmpty() ? tagAtom : NS_Atomize(extension);
|
||||
cloneElem->SetCustomElementData(new CustomElementData(typeAtom));
|
||||
CustomElementDefinition* definition =
|
||||
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
|
||||
nodeInfo->LocalName(),
|
||||
nodeInfo->NamespaceID());
|
||||
nodeInfo->NamespaceID(),
|
||||
typeAtom);
|
||||
if (definition) {
|
||||
elem->SetCustomElementData(new CustomElementData(tagAtom));
|
||||
nsContentUtils::EnqueueUpgradeReaction(elem, definition);
|
||||
}
|
||||
} else {
|
||||
// Check if node may be custom element by type extension.
|
||||
// ex. <button is="x-button">
|
||||
nsAutoString extension;
|
||||
if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) &&
|
||||
!extension.IsEmpty()) {
|
||||
definition =
|
||||
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
|
||||
nodeInfo->LocalName(),
|
||||
nodeInfo->NamespaceID(),
|
||||
&extension);
|
||||
if (definition) {
|
||||
RefPtr<nsAtom> typeAtom = NS_Atomize(extension);
|
||||
elem->SetCustomElementData(new CustomElementData(typeAtom));
|
||||
nsContentUtils::EnqueueUpgradeReaction(elem, definition);
|
||||
}
|
||||
nsContentUtils::EnqueueUpgradeReaction(cloneElem, definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -536,7 +530,7 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
|
|||
// shadow-including inclusive descendants that is custom.
|
||||
Element* element = aNode->IsElement() ? aNode->AsElement() : nullptr;
|
||||
if (element) {
|
||||
RefPtr<CustomElementData> data = element->GetCustomElementData();
|
||||
CustomElementData* data = element->GetCustomElementData();
|
||||
if (data && data->mState == CustomElementData::State::eCustom) {
|
||||
LifecycleAdoptedCallbackArgs args = {
|
||||
oldDoc,
|
||||
|
|
|
@ -311,6 +311,7 @@ static_assert(nsIContentPolicy::TYPE_INVALID == 0 &&
|
|||
nsIContentPolicy::TYPE_FETCH == 20 &&
|
||||
nsIContentPolicy::TYPE_IMAGESET == 21 &&
|
||||
nsIContentPolicy::TYPE_WEB_MANIFEST == 22 &&
|
||||
nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD == 43 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_SCRIPT == 23 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_WORKER == 24 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER == 25 &&
|
||||
|
|
|
@ -98,6 +98,7 @@ ClientManager::Shutdown()
|
|||
|
||||
UniquePtr<ClientSource>
|
||||
ClientManager::CreateSourceInternal(ClientType aType,
|
||||
nsISerialEventTarget* aEventTarget,
|
||||
const PrincipalInfo& aPrincipal)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(ClientManager);
|
||||
|
@ -113,7 +114,7 @@ ClientManager::CreateSourceInternal(ClientType aType,
|
|||
}
|
||||
|
||||
ClientSourceConstructorArgs args(id, aType, aPrincipal, TimeStamp::Now());
|
||||
UniquePtr<ClientSource> source(new ClientSource(this, args));
|
||||
UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
|
||||
source->Activate(GetActor());
|
||||
|
||||
return Move(source);
|
||||
|
@ -210,7 +211,8 @@ ClientManager::Startup()
|
|||
|
||||
// static
|
||||
UniquePtr<ClientSource>
|
||||
ClientManager::CreateSource(ClientType aType, nsIPrincipal* aPrincipal)
|
||||
ClientManager::CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
@ -222,15 +224,16 @@ ClientManager::CreateSource(ClientType aType, nsIPrincipal* aPrincipal)
|
|||
}
|
||||
|
||||
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
|
||||
return mgr->CreateSourceInternal(aType, principalInfo);
|
||||
return mgr->CreateSourceInternal(aType, aEventTarget, principalInfo);
|
||||
}
|
||||
|
||||
// static
|
||||
UniquePtr<ClientSource>
|
||||
ClientManager::CreateSource(ClientType aType, const PrincipalInfo& aPrincipal)
|
||||
ClientManager::CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
|
||||
const PrincipalInfo& aPrincipal)
|
||||
{
|
||||
RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
|
||||
return mgr->CreateSourceInternal(aType, aPrincipal);
|
||||
return mgr->CreateSourceInternal(aType, aEventTarget, aPrincipal);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
|
||||
#include "mozilla/dom/ClientOpPromise.h"
|
||||
#include "mozilla/dom/ClientThing.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PBackgroundChild;
|
||||
class PrincipalInfo;
|
||||
} // namespace ipc
|
||||
namespace dom {
|
||||
|
||||
|
@ -48,6 +49,7 @@ class ClientManager final : public ClientThing<ClientManagerChild>
|
|||
|
||||
UniquePtr<ClientSource>
|
||||
CreateSourceInternal(ClientType aType,
|
||||
nsISerialEventTarget* aEventTarget,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipal);
|
||||
|
||||
already_AddRefed<ClientHandle>
|
||||
|
@ -79,10 +81,12 @@ public:
|
|||
Startup();
|
||||
|
||||
static UniquePtr<ClientSource>
|
||||
CreateSource(ClientType aType, nsIPrincipal* aPrincipal);
|
||||
CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
static UniquePtr<ClientSource>
|
||||
CreateSource(ClientType aType, const mozilla::ipc::PrincipalInfo& aPrincipal);
|
||||
CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipal);
|
||||
|
||||
static already_AddRefed<ClientHandle>
|
||||
CreateHandle(const ClientInfo& aClientInfo,
|
||||
|
|
|
@ -75,12 +75,15 @@ ClientSource::GetDocShell() const
|
|||
}
|
||||
|
||||
ClientSource::ClientSource(ClientManager* aManager,
|
||||
nsISerialEventTarget* aEventTarget,
|
||||
const ClientSourceConstructorArgs& aArgs)
|
||||
: mManager(aManager)
|
||||
, mEventTarget(aEventTarget)
|
||||
, mOwner(AsVariant(Nothing()))
|
||||
, mClientInfo(aArgs.id(), aArgs.type(), aArgs.principalInfo(), aArgs.creationTime())
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
MOZ_ASSERT(mEventTarget);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -232,5 +235,17 @@ ClientSource::DocShellExecutionReady(nsIDocShell* aDocShell)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
const ClientInfo&
|
||||
ClientSource::Info() const
|
||||
{
|
||||
return mClientInfo;
|
||||
}
|
||||
|
||||
nsISerialEventTarget*
|
||||
ClientSource::EventTarget() const
|
||||
{
|
||||
return mEventTarget;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -38,6 +38,7 @@ class ClientSource final : public ClientThing<ClientSourceChild>
|
|||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
RefPtr<ClientManager> mManager;
|
||||
nsCOMPtr<nsISerialEventTarget> mEventTarget;
|
||||
|
||||
Variant<Nothing,
|
||||
RefPtr<nsPIDOMWindowInner>,
|
||||
|
@ -60,6 +61,7 @@ class ClientSource final : public ClientThing<ClientSourceChild>
|
|||
|
||||
// Private methods called by ClientManager
|
||||
ClientSource(ClientManager* aManager,
|
||||
nsISerialEventTarget* aEventTarget,
|
||||
const ClientSourceConstructorArgs& aArgs);
|
||||
|
||||
void
|
||||
|
@ -79,6 +81,12 @@ public:
|
|||
|
||||
nsresult
|
||||
DocShellExecutionReady(nsIDocShell* aDocShell);
|
||||
|
||||
const ClientInfo&
|
||||
Info() const;
|
||||
|
||||
nsISerialEventTarget*
|
||||
EventTarget() const;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -324,6 +324,9 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
|
|||
case nsIContentPolicy::TYPE_WEB_MANIFEST:
|
||||
context = RequestContext::Manifest;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD:
|
||||
context = RequestContext::Internal;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unhandled nsContentPolicyType value");
|
||||
break;
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace dom {
|
|||
* image | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_IMAGE_FAVICON
|
||||
* imageset | TYPE_IMAGESET
|
||||
* import | Not supported by Gecko
|
||||
* internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
|
||||
* internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER, TYPE_SAVEAS_DOWNLOAD
|
||||
* location |
|
||||
* manifest | TYPE_WEB_MANIFEST
|
||||
* object | TYPE_INTERNAL_OBJECT
|
||||
|
|
|
@ -259,6 +259,8 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
|||
RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
|
||||
|
||||
nsAtom *name = nodeInfo->NameAtom();
|
||||
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
|
||||
RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
|
||||
|
||||
NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
|
||||
"Trying to HTML elements that don't have the XHTML namespace");
|
||||
|
@ -275,7 +277,7 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
|||
nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
|
||||
nodeInfo->LocalName(),
|
||||
nodeInfo->NamespaceID(),
|
||||
aIs);
|
||||
typeAtom);
|
||||
}
|
||||
|
||||
// It might be a problem that parser synchronously calls constructor, so filed
|
||||
|
@ -318,8 +320,6 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
|||
// SetupCustomElement() should be called with an element that don't have
|
||||
// CustomElementData setup, if not we will hit the assertion in
|
||||
// SetCustomElementData().
|
||||
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
|
||||
RefPtr<nsAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
|
||||
// Built-in element
|
||||
*aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
|
||||
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
|
||||
|
@ -369,7 +369,7 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
|
|||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled() &&
|
||||
(isCustomElementName || aIs)) {
|
||||
nsContentUtils::SetupCustomElement(*aResult, aIs);
|
||||
(*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -18,4 +18,5 @@ support-files =
|
|||
[browser_permissionsPromptDeny.js]
|
||||
[browser_permissionsPromptWorker.js]
|
||||
[browser_perwindow_privateBrowsing.js]
|
||||
skip-if = os == 'linux' && debug # bug 1394671
|
||||
[browser_bug839193.js]
|
||||
|
|
|
@ -103,11 +103,11 @@ skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emula
|
|||
[test_peerConnection_checkPacketDumpHook.html]
|
||||
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_basicAudioNATSrflx.html]
|
||||
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
|
||||
skip-if = toolkit == 'android' || (os == 'linux' && debug) # websockets don't work on android (bug 1266217), linux hang (bug 1339568)
|
||||
[test_peerConnection_basicAudioNATRelay.html]
|
||||
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
|
||||
skip-if = toolkit == 'android' || (os == 'linux' && debug) # websockets don't work on android (bug 1266217), linux hang (bug 1339568)
|
||||
[test_peerConnection_basicAudioNATRelayTCP.html]
|
||||
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
|
||||
skip-if = toolkit == 'android' || (os == 'linux' && debug) # websockets don't work on android (bug 1266217), linux hang (bug 1339568)
|
||||
[test_peerConnection_basicAudioNATRelayTLS.html]
|
||||
skip-if = true # need pyopenssl on builders, see bug 1323439 # toolkit == 'android' # websockets don't work on android (bug 1266217)
|
||||
[test_peerConnection_basicAudioRequireEOC.html]
|
||||
|
@ -115,7 +115,7 @@ skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emula
|
|||
[test_peerConnection_basicAudioPcmaPcmuOnly.html]
|
||||
skip-if = android_version == '18'
|
||||
[test_peerConnection_basicAudioDynamicPtMissingRtpmap.html]
|
||||
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
skip-if = (android_version == '18') || (os == 'linux' && debug) # android(Bug 1189784, timeouts on 4.3 emulator), linux hang (bug 1339568)
|
||||
[test_peerConnection_basicAudioVerifyRtpHeaderExtensions.html]
|
||||
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_basicAudioVideo.html]
|
||||
|
|
|
@ -480,6 +480,12 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
|
|||
break;
|
||||
}
|
||||
|
||||
case nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD: {
|
||||
mimeTypeGuess = EmptyCString();
|
||||
requestingContext = aLoadInfo->LoadingNode();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// nsIContentPolicy::TYPE_INVALID
|
||||
MOZ_ASSERT(false, "can not perform security check without a valid contentType");
|
||||
|
|
|
@ -576,6 +576,13 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
|
||||
// Creating insecure connections for a save-as link download is acceptable.
|
||||
// This download is completely disconnected from the docShell, but still
|
||||
// using the same loading principal.
|
||||
case TYPE_SAVEAS_DOWNLOAD:
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
|
||||
// Static display content is considered moderate risk for mixed content so
|
||||
// these will be blocked according to the mixed display preference
|
||||
case TYPE_IMAGE:
|
||||
|
|
|
@ -8,6 +8,7 @@ function test_upgrade(f, msg) {
|
|||
// Run upgrading test on an element created by document.createElement.
|
||||
test_with_new_window(function(testWindow, testMsg) {
|
||||
let element = testWindow.document.createElement('unresolved-element');
|
||||
testWindow.document.documentElement.appendChild(element);
|
||||
f(testWindow, element, testMsg);
|
||||
}, msg + ' (document.createElement)');
|
||||
}
|
||||
|
@ -21,6 +22,14 @@ test_upgrade(function(testWindow, testElement, msg) {
|
|||
MyCustomElement.prototype, msg);
|
||||
}, 'Custom element must be upgraded if there is a matching definition');
|
||||
|
||||
test_upgrade(function(testWindow, testElement, msg) {
|
||||
testElement.remove();
|
||||
class MyCustomElement extends testWindow.HTMLElement {};
|
||||
testWindow.customElements.define('unresolved-element', MyCustomElement);
|
||||
SimpleTest.is(Object.getPrototypeOf(testElement),
|
||||
testWindow.HTMLElement.prototype, msg);
|
||||
}, 'Custom element must not be upgraded if it has been removed from tree');
|
||||
|
||||
test_upgrade(function(testWindow, testElement, msg) {
|
||||
let exceptionToThrow = {name: 'exception thrown by a custom constructor'};
|
||||
class ThrowCustomElement extends testWindow.HTMLElement {
|
||||
|
|
|
@ -25,8 +25,6 @@ using mozilla::dom::CreateECParamsForCurve;
|
|||
|
||||
const nsCString U2FSoftTokenManager::mSecretNickname =
|
||||
NS_LITERAL_CSTRING("U2F_NSSTOKEN");
|
||||
const nsString U2FSoftTokenManager::mVersion =
|
||||
NS_LITERAL_STRING("U2F_V2");
|
||||
|
||||
namespace {
|
||||
NS_NAMED_LITERAL_CSTRING(kAttestCertSubjectName, "CN=Firefox U2F Soft Token");
|
||||
|
@ -575,13 +573,6 @@ PrivateKeyFromKeyHandle(const UniquePK11SlotInfo& aSlot,
|
|||
return unwrappedKey;
|
||||
}
|
||||
|
||||
// Return whether the provided version is supported by this token.
|
||||
bool
|
||||
U2FSoftTokenManager::IsCompatibleVersion(const nsAString& aVersion)
|
||||
{
|
||||
return mVersion == aVersion;
|
||||
}
|
||||
|
||||
// IsRegistered determines if the provided key handle is usable by this token.
|
||||
nsresult
|
||||
U2FSoftTokenManager::IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
|
||||
|
|
|
@ -46,7 +46,6 @@ public:
|
|||
private:
|
||||
~U2FSoftTokenManager();
|
||||
nsresult Init();
|
||||
bool IsCompatibleVersion(const nsAString& aVersion);
|
||||
|
||||
nsresult IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
|
||||
const nsTArray<uint8_t>& aAppParam,
|
||||
|
@ -56,7 +55,6 @@ private:
|
|||
mozilla::UniquePK11SymKey mWrappingKey;
|
||||
|
||||
static const nsCString mSecretNickname;
|
||||
static const nsString mVersion;
|
||||
|
||||
nsresult GetOrCreateWrappingKey(const mozilla::UniquePK11SlotInfo& aSlot,
|
||||
const nsNSSShutDownPreventionLock&);
|
||||
|
|
|
@ -48,7 +48,7 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument,
|
|||
*aDidPrettyPrint = false;
|
||||
|
||||
// Check for iframe with display:none. Such iframes don't have presshells
|
||||
nsIPresShell* shell = aDocument->GetShell();
|
||||
nsCOMPtr<nsIPresShell> shell = aDocument->GetShell();
|
||||
if (!shell) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -153,7 +153,8 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument,
|
|||
GetSystemPrincipal(getter_AddRefs(sysPrincipal));
|
||||
|
||||
// Destroy any existing frames before we unbind anonymous content.
|
||||
if (rootCont->IsElement()) {
|
||||
// Note that the shell might be Destroy'ed by now (see bug 1415541).
|
||||
if (!shell->IsDestroying() && rootCont->IsElement()) {
|
||||
shell->DestroyFramesForAndRestyle(rootCont->AsElement());
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ GPUProcessManager::GPUProcessManager()
|
|||
mNumProcessAttempts(0),
|
||||
mDeviceResetCount(0),
|
||||
mProcess(nullptr),
|
||||
mProcessToken(0),
|
||||
mGPUChild(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GPUProcessManager);
|
||||
|
|
|
@ -281,7 +281,7 @@ private:
|
|||
|
||||
// Fields that are associated with the current GPU process.
|
||||
GPUProcessHost* mProcess;
|
||||
MOZ_INIT_OUTSIDE_CTOR uint64_t mProcessToken;
|
||||
uint64_t mProcessToken;
|
||||
GPUChild* mGPUChild;
|
||||
RefPtr<VsyncBridgeChild> mVsyncBridge;
|
||||
};
|
||||
|
|
|
@ -2751,47 +2751,21 @@ js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind co
|
|||
return true;
|
||||
}
|
||||
|
||||
enum class ResumeNextKind {
|
||||
Enqueue, Reject, Resolve
|
||||
};
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
|
||||
AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
ResumeNextKind kind, HandleValue valueOrException = UndefinedHandleValue,
|
||||
bool done = false);
|
||||
|
||||
// Async Iteration proposal 11.4.3.3.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value, bool done)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
|
||||
|
||||
// Step 4.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
asyncGenObj->cacheRequest(request);
|
||||
|
||||
// Step 6.
|
||||
RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
|
||||
if (!resultObj)
|
||||
return false;
|
||||
|
||||
RootedValue resultValue(cx, ObjectValue(*resultObj));
|
||||
|
||||
// Step 7.
|
||||
if (!ResolvePromiseInternal(cx, resultPromise, resultValue))
|
||||
return false;
|
||||
|
||||
// Step 8.
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
|
||||
return false;
|
||||
|
||||
// Step 9.
|
||||
return true;
|
||||
return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Resolve, value, done);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.4.3.4.
|
||||
|
@ -2799,123 +2773,188 @@ MOZ_MUST_USE bool
|
|||
js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue exception)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
|
||||
|
||||
// Step 4.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
asyncGenObj->cacheRequest(request);
|
||||
|
||||
// Step 6.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
|
||||
return false;
|
||||
|
||||
// Step 7.
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
|
||||
return false;
|
||||
|
||||
// Step 8.
|
||||
return true;
|
||||
return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Reject, exception);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.4.3.5.
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
|
||||
AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
ResumeNextKind kind,
|
||||
HandleValue valueOrException_ /* = UndefinedHandleValue */,
|
||||
bool done /* = false */)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
RootedValue valueOrException(cx, valueOrException_);
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isExecuting());
|
||||
while (true) {
|
||||
switch (kind) {
|
||||
case ResumeNextKind::Enqueue:
|
||||
// No further action required.
|
||||
break;
|
||||
case ResumeNextKind::Reject: {
|
||||
// 11.4.3.4 AsyncGeneratorReject ( generator, exception )
|
||||
HandleValue exception = valueOrException;
|
||||
|
||||
// Step 4.
|
||||
if (asyncGenObj->isAwaitingYieldReturn() || asyncGenObj->isAwaitingReturn())
|
||||
return true;
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 5-6.
|
||||
if (asyncGenObj->isQueueEmpty())
|
||||
return true;
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
|
||||
|
||||
// Steps 7-8.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
// Step 4.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 9.
|
||||
CompletionKind completionKind = request->completionKind();
|
||||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
// Step 10.
|
||||
if (completionKind != CompletionKind::Normal) {
|
||||
// Step 10.a.
|
||||
if (asyncGenObj->isSuspendedStart())
|
||||
asyncGenObj->setCompleted();
|
||||
asyncGenObj->cacheRequest(request);
|
||||
|
||||
// Step 10.b.
|
||||
if (asyncGenObj->isCompleted()) {
|
||||
RootedValue value(cx, request->completionValue());
|
||||
// Step 6.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
|
||||
return false;
|
||||
|
||||
// Step 10.b.i.
|
||||
if (completionKind == CompletionKind::Return) {
|
||||
// Steps 10.b.i.1.
|
||||
asyncGenObj->setAwaitingReturn();
|
||||
// Steps 7-8.
|
||||
break;
|
||||
}
|
||||
case ResumeNextKind::Resolve: {
|
||||
// 11.4.3.3 AsyncGeneratorResolve ( generator, value, done )
|
||||
HandleValue value = valueOrException;
|
||||
|
||||
// Steps 10.b.i.4-6 (reordered).
|
||||
RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled));
|
||||
RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorResumeNextReturnRejected));
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 10.b.i.2-3, 7-10.
|
||||
auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
|
||||
reaction->setIsAsyncGenerator(asyncGenObj);
|
||||
};
|
||||
return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
|
||||
}
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
|
||||
|
||||
// Step 10.b.ii.1.
|
||||
MOZ_ASSERT(completionKind == CompletionKind::Throw);
|
||||
// Step 4.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Steps 10.b.ii.2-3.
|
||||
return AsyncGeneratorReject(cx, asyncGenObj, value);
|
||||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
asyncGenObj->cacheRequest(request);
|
||||
|
||||
// Step 6.
|
||||
RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
|
||||
if (!resultObj)
|
||||
return false;
|
||||
|
||||
RootedValue resultValue(cx, ObjectValue(*resultObj));
|
||||
|
||||
// Step 7.
|
||||
if (!ResolvePromiseInternal(cx, resultPromise, resultValue))
|
||||
return false;
|
||||
|
||||
// Steps 8-9.
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (asyncGenObj->isCompleted()) {
|
||||
// Step 11.
|
||||
return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
|
||||
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isExecuting());
|
||||
|
||||
// Step 4.
|
||||
if (asyncGenObj->isAwaitingYieldReturn() || asyncGenObj->isAwaitingReturn())
|
||||
return true;
|
||||
|
||||
// Steps 5-6.
|
||||
if (asyncGenObj->isQueueEmpty())
|
||||
return true;
|
||||
|
||||
// Steps 7-8.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 9.
|
||||
CompletionKind completionKind = request->completionKind();
|
||||
|
||||
// Step 10.
|
||||
if (completionKind != CompletionKind::Normal) {
|
||||
// Step 10.a.
|
||||
if (asyncGenObj->isSuspendedStart())
|
||||
asyncGenObj->setCompleted();
|
||||
|
||||
// Step 10.b.
|
||||
if (asyncGenObj->isCompleted()) {
|
||||
RootedValue value(cx, request->completionValue());
|
||||
|
||||
// Step 10.b.i.
|
||||
if (completionKind == CompletionKind::Return) {
|
||||
// Steps 10.b.i.1.
|
||||
asyncGenObj->setAwaitingReturn();
|
||||
|
||||
// Steps 10.b.i.4-6 (reordered).
|
||||
static constexpr int32_t ResumeNextReturnFulfilled =
|
||||
PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled;
|
||||
static constexpr int32_t ResumeNextReturnRejected =
|
||||
PromiseHandlerAsyncGeneratorResumeNextReturnRejected;
|
||||
|
||||
RootedValue onFulfilled(cx, Int32Value(ResumeNextReturnFulfilled));
|
||||
RootedValue onRejected(cx, Int32Value(ResumeNextReturnRejected));
|
||||
|
||||
// Steps 10.b.i.2-3, 7-10.
|
||||
auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
|
||||
reaction->setIsAsyncGenerator(asyncGenObj);
|
||||
};
|
||||
return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
|
||||
}
|
||||
|
||||
// Step 10.b.ii.1.
|
||||
MOZ_ASSERT(completionKind == CompletionKind::Throw);
|
||||
|
||||
// Steps 10.b.ii.2-3.
|
||||
kind = ResumeNextKind::Reject;
|
||||
valueOrException.set(value);
|
||||
// |done| is unused for ResumeNextKind::Reject.
|
||||
continue;
|
||||
}
|
||||
} else if (asyncGenObj->isCompleted()) {
|
||||
// Step 11.
|
||||
kind = ResumeNextKind::Resolve;
|
||||
valueOrException.setUndefined();
|
||||
done = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 12.
|
||||
MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
|
||||
|
||||
// Step 16 (reordered).
|
||||
asyncGenObj->setExecuting();
|
||||
|
||||
RootedValue argument(cx, request->completionValue());
|
||||
|
||||
if (completionKind == CompletionKind::Return) {
|
||||
// 11.4.3.7 AsyncGeneratorYield step 8.b-e.
|
||||
// Since we don't have the place that handles return from yield
|
||||
// inside the generator, handle the case here, with extra state
|
||||
// State_AwaitingYieldReturn.
|
||||
asyncGenObj->setAwaitingYieldReturn();
|
||||
|
||||
static constexpr int32_t YieldReturnAwaitedFulfilled =
|
||||
PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled;
|
||||
static constexpr int32_t YieldReturnAwaitedRejected =
|
||||
PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected;
|
||||
|
||||
RootedValue onFulfilled(cx, Int32Value(YieldReturnAwaitedFulfilled));
|
||||
RootedValue onRejected(cx, Int32Value(YieldReturnAwaitedRejected));
|
||||
|
||||
auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
|
||||
reaction->setIsAsyncGenerator(asyncGenObj);
|
||||
};
|
||||
return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected, extra);
|
||||
}
|
||||
|
||||
// Steps 13-15, 17-21.
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
|
||||
}
|
||||
|
||||
// Step 12.
|
||||
MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
|
||||
|
||||
// Step 16 (reordered).
|
||||
asyncGenObj->setExecuting();
|
||||
|
||||
RootedValue argument(cx, request->completionValue());
|
||||
|
||||
if (completionKind == CompletionKind::Return) {
|
||||
// 11.4.3.7 AsyncGeneratorYield step 8.b-e.
|
||||
// Since we don't have the place that handles return from yield
|
||||
// inside the generator, handle the case here, with extra state
|
||||
// State_AwaitingYieldReturn.
|
||||
asyncGenObj->setAwaitingYieldReturn();
|
||||
|
||||
RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled));
|
||||
RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected));
|
||||
|
||||
auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
|
||||
reaction->setIsAsyncGenerator(asyncGenObj);
|
||||
};
|
||||
return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected, extra);
|
||||
}
|
||||
|
||||
// Steps 13-15, 17-21.
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.4.3.6.
|
||||
|
@ -2964,7 +3003,7 @@ js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
|
|||
// Step 7.
|
||||
if (!asyncGenObj->isExecuting()) {
|
||||
// Step 8.
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Enqueue))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/IntegerTypeTraits.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -37,6 +38,11 @@ using mozilla::IsFinite;
|
|||
using mozilla::IsNaN;
|
||||
using mozilla::FloorLog2;
|
||||
using mozilla::NumberIsInt32;
|
||||
using mozilla::EnableIf;
|
||||
using mozilla::IsIntegral;
|
||||
using mozilla::IsFloatingPoint;
|
||||
using mozilla::IsSigned;
|
||||
using mozilla::MakeUnsigned;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// SIMD
|
||||
|
@ -723,6 +729,21 @@ FOR_EACH_SIMD(InstantiateCreateSimd_)
|
|||
#undef FOR_EACH_SIMD
|
||||
|
||||
namespace js {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct MaybeMakeUnsigned {
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MaybeMakeUnsigned<T, typename EnableIf<IsIntegral<T>::value && IsSigned<T>::value>::Type> {
|
||||
using Type = typename MakeUnsigned<T>::Type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Unary SIMD operators
|
||||
template<typename T>
|
||||
struct Identity {
|
||||
|
@ -734,7 +755,8 @@ struct Abs {
|
|||
};
|
||||
template<typename T>
|
||||
struct Neg {
|
||||
static T apply(T x) { return -1 * x; }
|
||||
using MaybeUnsignedT = typename detail::MaybeMakeUnsigned<T>::Type;
|
||||
static T apply(T x) { return MaybeUnsignedT(-1) * MaybeUnsignedT(x); }
|
||||
};
|
||||
template<typename T>
|
||||
struct Not {
|
||||
|
@ -746,33 +768,40 @@ struct LogicalNot {
|
|||
};
|
||||
template<typename T>
|
||||
struct RecApprox {
|
||||
static_assert(IsFloatingPoint<T>::value, "RecApprox only supported for floating points");
|
||||
static T apply(T x) { return 1 / x; }
|
||||
};
|
||||
template<typename T>
|
||||
struct RecSqrtApprox {
|
||||
static_assert(IsFloatingPoint<T>::value, "RecSqrtApprox only supported for floating points");
|
||||
static T apply(T x) { return 1 / sqrt(x); }
|
||||
};
|
||||
template<typename T>
|
||||
struct Sqrt {
|
||||
static_assert(IsFloatingPoint<T>::value, "Sqrt only supported for floating points");
|
||||
static T apply(T x) { return sqrt(x); }
|
||||
};
|
||||
|
||||
// Binary SIMD operators
|
||||
template<typename T>
|
||||
struct Add {
|
||||
static T apply(T l, T r) { return l + r; }
|
||||
using MaybeUnsignedT = typename detail::MaybeMakeUnsigned<T>::Type;
|
||||
static T apply(T l, T r) { return MaybeUnsignedT(l) + MaybeUnsignedT(r); }
|
||||
};
|
||||
template<typename T>
|
||||
struct Sub {
|
||||
static T apply(T l, T r) { return l - r; }
|
||||
using MaybeUnsignedT = typename detail::MaybeMakeUnsigned<T>::Type;
|
||||
static T apply(T l, T r) { return MaybeUnsignedT(l) - MaybeUnsignedT(r); }
|
||||
};
|
||||
template<typename T>
|
||||
struct Div {
|
||||
static_assert(IsFloatingPoint<T>::value, "Div only supported for floating points");
|
||||
static T apply(T l, T r) { return l / r; }
|
||||
};
|
||||
template<typename T>
|
||||
struct Mul {
|
||||
static T apply(T l, T r) { return l * r; }
|
||||
using MaybeUnsignedT = typename detail::MaybeMakeUnsigned<T>::Type;
|
||||
static T apply(T l, T r) { return MaybeUnsignedT(l) * MaybeUnsignedT(r); }
|
||||
};
|
||||
template<typename T>
|
||||
struct Minimum {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
autospider.py is intended both as the harness for running automation builds, as
|
||||
well as a way to easily reproduce automation builds on a developer workstation.
|
||||
Some brave souls also use it as the basis for doing their normal local builds.
|
||||
|
||||
Basic usage:
|
||||
|
||||
./js/src/devtools/automation/autospider.py plain
|
||||
|
||||
The script may be run from any directory. This will configure and build the
|
||||
source, then run a series of tests. See the --help message for many different
|
||||
ways of suppressing various actions or changing the output.
|
||||
|
||||
The different possible build+test configurations are controlled mostly by JSON
|
||||
files in a variants/ directory (eg there is a .../variants/plain file for the
|
||||
above command).
|
||||
|
||||
In automation, the test jobs will run with a dynamically loaded library that
|
||||
catches crashes and generates minidumps, so that autospider.py can produce a
|
||||
readable stack trace at the end of the run. Currently this library is only
|
||||
available on linux64, and is built via the following procedure:
|
||||
|
||||
% git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
% export PATH=$PATH:$(pwd)/depot_tools
|
||||
% mkdir breakpad
|
||||
% cd breakpad
|
||||
% fetch breakpad
|
||||
% cd src
|
||||
% git fetch https://github.com/hotsphink/breakpad injector
|
||||
% git checkout injector
|
||||
% cd ..
|
||||
% mkdir obj
|
||||
% cd obj
|
||||
% ../src/configure
|
||||
% mkdir ../root
|
||||
% make install DESTDIR=$(pwd)/../root
|
||||
|
||||
The shared library will now be in root/usr/local/lib64/libbreakpadinjector.so
|
|
@ -44,8 +44,6 @@ ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
|
|||
ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
|
||||
ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
|
||||
ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
|
||||
ecma_6/Comprehensions/sudoku.js
|
||||
js1_8_5/extensions/clone-complex-object.js
|
||||
js1_8_5/reflect-parse/classes.js
|
||||
js1_8_5/reflect-parse/destructuring-variable-declarations.js
|
||||
js1_8_5/regress/no-array-comprehension-length-limit.js
|
||||
|
|
|
@ -23,7 +23,7 @@ def directories(pathmodule, cwd, fixup=lambda s: s):
|
|||
js_src = pathmodule.abspath(pathmodule.join(scripts, "..", ".."))
|
||||
source = pathmodule.abspath(pathmodule.join(js_src, "..", ".."))
|
||||
tooltool = pathmodule.abspath(env.get('TOOLTOOL_CHECKOUT',
|
||||
pathmodule.join(source, "..")))
|
||||
pathmodule.join(source, "..", "..")))
|
||||
return Dirs(scripts, js_src, source, tooltool)
|
||||
|
||||
# Some scripts will be called with sh, which cannot use backslashed
|
||||
|
@ -92,7 +92,6 @@ POBJDIR = posixpath.join(PDIR.source, args.objdir)
|
|||
AUTOMATION = env.get('AUTOMATION', False)
|
||||
MAKE = env.get('MAKE', 'make')
|
||||
MAKEFLAGS = env.get('MAKEFLAGS', '-j6' + ('' if AUTOMATION else ' -s'))
|
||||
UNAME_M = subprocess.check_output(['uname', '-m']).strip()
|
||||
|
||||
|
||||
def set_vars_from_script(script, vars):
|
||||
|
@ -207,7 +206,7 @@ if word_bits is None and args.platform:
|
|||
|
||||
# Fall back to the word size of the host.
|
||||
if word_bits is None:
|
||||
word_bits = 64 if UNAME_M == 'x86_64' else 32
|
||||
word_bits = 64 if platform.architecture()[0] == '64bit' else 32
|
||||
|
||||
if 'compiler' in variant:
|
||||
compiler = variant['compiler']
|
||||
|
@ -256,11 +255,11 @@ if word_bits == 32:
|
|||
if platform.system() == 'Windows':
|
||||
CONFIGURE_ARGS += ' --target=i686-pc-mingw32 --host=i686-pc-mingw32'
|
||||
elif platform.system() == 'Linux':
|
||||
if UNAME_M != 'arm':
|
||||
if not platform.machine().startswith('arm'):
|
||||
CONFIGURE_ARGS += ' --target=i686-pc-linux --host=i686-pc-linux'
|
||||
|
||||
# Add SSE2 support for x86/x64 architectures.
|
||||
if UNAME_M != 'arm':
|
||||
if not platform.machine().startswith('arm'):
|
||||
if platform.system() == 'Windows':
|
||||
sse_flags = '-arch:SSE2'
|
||||
else:
|
||||
|
@ -289,7 +288,8 @@ ensure_dir_exists(OUTDIR, clobber=not args.keep)
|
|||
|
||||
|
||||
def run_command(command, check=False, **kwargs):
|
||||
proc = Popen(command, cwd=OBJDIR, **kwargs)
|
||||
kwargs.setdefault('cwd', OBJDIR)
|
||||
proc = Popen(command, **kwargs)
|
||||
ACTIVE_PROCESSES.add(proc)
|
||||
stdout, stderr = None, None
|
||||
try:
|
||||
|
@ -304,13 +304,34 @@ def run_command(command, check=False, **kwargs):
|
|||
# Add in environment variable settings for this variant. Normally used to
|
||||
# modify the flags passed to the shell or to set the GC zeal mode.
|
||||
for k, v in variant.get('env', {}).items():
|
||||
env[k] = v.format(
|
||||
env[k.encode('ascii')] = v.encode('ascii').format(
|
||||
DIR=DIR.scripts,
|
||||
TOOLTOOL_CHECKOUT=DIR.tooltool,
|
||||
MOZ_UPLOAD_DIR=env['MOZ_UPLOAD_DIR'],
|
||||
OUTDIR=OUTDIR,
|
||||
)
|
||||
|
||||
if AUTOMATION:
|
||||
# Currently only supported on linux64.
|
||||
if platform.system() == 'Linux' and platform.machine() == 'x86_64':
|
||||
use_minidump = variant.get('use_minidump', True)
|
||||
else:
|
||||
use_minidump = False
|
||||
else:
|
||||
use_minidump = False
|
||||
|
||||
if use_minidump:
|
||||
env.setdefault('MINIDUMP_SAVE_PATH', env['MOZ_UPLOAD_DIR'])
|
||||
injector_lib = None
|
||||
if platform.system() == 'Linux':
|
||||
injector_lib = os.path.join(DIR.tooltool, 'breakpad-tools', 'libbreakpadinjector.so')
|
||||
env.setdefault('MINIDUMP_STACKWALK',
|
||||
os.path.join(DIR.tooltool, 'linux64-minidump_stackwalk'))
|
||||
elif platform.system() == 'Darwin':
|
||||
injector_lib = os.path.join(DIR.tooltool, 'breakpad-tools', 'breakpadinjector.dylib')
|
||||
if not injector_lib or not os.path.exists(injector_lib):
|
||||
use_minidump=False
|
||||
|
||||
def need_updating_configure(configure):
|
||||
if not os.path.exists(configure):
|
||||
return True
|
||||
|
@ -342,10 +363,23 @@ if not args.nobuild:
|
|||
# Run make
|
||||
run_command('%s -w %s' % (MAKE, MAKEFLAGS), shell=True, check=True)
|
||||
|
||||
if use_minidump:
|
||||
# Convert symbols to breakpad format.
|
||||
hostdir = os.path.join(OBJDIR, "dist", "host", "bin")
|
||||
os.makedirs(hostdir)
|
||||
shutil.copy(os.path.join(DIR.tooltool, "breakpad-tools", "dump_syms"),
|
||||
os.path.join(hostdir, 'dump_syms'))
|
||||
run_command([
|
||||
'make',
|
||||
'recurse_syms',
|
||||
'MOZ_SOURCE_REPO=file://' + DIR.source,
|
||||
'RUST_TARGET=0', 'RUSTC_COMMIT=0'
|
||||
], check=True)
|
||||
|
||||
COMMAND_PREFIX = []
|
||||
# On Linux, disable ASLR to make shell builds a bit more reproducible.
|
||||
if subprocess.call("type setarch >/dev/null 2>&1", shell=True) == 0:
|
||||
COMMAND_PREFIX.extend(['setarch', UNAME_M, '-R'])
|
||||
COMMAND_PREFIX.extend(['setarch', platform.machine(), '-R'])
|
||||
|
||||
|
||||
def run_test_command(command, **kwargs):
|
||||
|
@ -392,6 +426,15 @@ if 'all' in args.skip_tests.split(","):
|
|||
if platform.system() == 'Windows':
|
||||
env['JITTEST_EXTRA_ARGS'] = "-j1 " + env.get('JITTEST_EXTRA_ARGS', '')
|
||||
|
||||
if use_minidump:
|
||||
# Set up later js invocations to run with the breakpad injector loaded.
|
||||
# Originally, I intended for this to be used with LD_PRELOAD, but when
|
||||
# cross-compiling from 64- to 32-bit, that will fail and produce stderr
|
||||
# output when running any 64-bit commands, which breaks eg mozconfig
|
||||
# processing. So use the --dll command line mechanism universally.
|
||||
for v in ('JSTESTS_EXTRA_ARGS', 'JITTEST_EXTRA_ARGS'):
|
||||
env[v] = "--args='--dll %s' %s" % (injector_lib, env.get(v, ''))
|
||||
|
||||
# Always run all enabled tests, even if earlier ones failed. But return the
|
||||
# first failed status.
|
||||
results = []
|
||||
|
@ -406,7 +449,10 @@ if 'jittest' in test_suites:
|
|||
results.append(run_test_command([MAKE, 'check-jit-test']))
|
||||
if 'jsapitests' in test_suites:
|
||||
jsapi_test_binary = os.path.join(OBJDIR, 'dist', 'bin', 'jsapi-tests')
|
||||
st = run_test_command([jsapi_test_binary])
|
||||
test_env = env.copy()
|
||||
if use_minidump and platform.system() == 'Linux':
|
||||
test_env['LD_PRELOAD'] = injector_lib
|
||||
st = run_test_command([jsapi_test_binary], env=test_env)
|
||||
if st < 0:
|
||||
print("PROCESS-CRASH | jsapi-tests | application crashed")
|
||||
print("Return code: {}".format(st))
|
||||
|
@ -498,6 +544,16 @@ if args.variant in ('tsan', 'msan'):
|
|||
command += files
|
||||
subprocess.call(command)
|
||||
|
||||
# Generate stacks from minidumps.
|
||||
if use_minidump:
|
||||
venv_python = os.path.join(OBJDIR, "_virtualenv", "bin", "python")
|
||||
run_command([
|
||||
venv_python,
|
||||
os.path.join(DIR.source, "testing/mozbase/mozcrash/mozcrash/mozcrash.py"),
|
||||
os.getenv("TMPDIR", "/tmp"),
|
||||
os.path.join(OBJDIR, "dist/crashreporter-symbols"),
|
||||
])
|
||||
|
||||
for st in results:
|
||||
if st != 0:
|
||||
sys.exit(st)
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
"configure-args": "--enable-stdcxx-compat --enable-simulator=arm --target=i686-pc-linux --host=i686-pc-linux",
|
||||
"optimize": true,
|
||||
"debug": true,
|
||||
"bits": 32
|
||||
"bits": 32,
|
||||
"use_minidump": false
|
||||
}
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
"compiler": "clang",
|
||||
"env": {
|
||||
"LLVM_SYMBOLIZER": "{TOOLTOOL_CHECKOUT}/clang/bin/llvm-symbolizer"
|
||||
}
|
||||
},
|
||||
"use_minidump": false
|
||||
}
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
"JITTEST_EXTRA_ARGS": "--jitflags=none",
|
||||
"JSTESTS_EXTRA_ARGS": "--jitflags=none",
|
||||
"LLVM_SYMBOLIZER": "{TOOLTOOL_CHECKOUT}/clang/bin/llvm-symbolizer"
|
||||
}
|
||||
},
|
||||
"use_minidump": false
|
||||
}
|
||||
|
|
|
@ -730,7 +730,8 @@ frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
|
|||
scope = &cx->global()->emptyGlobalScope();
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope);
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::NotGenerator, SyncFunction,
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::NotGenerator,
|
||||
FunctionAsyncKind::SyncFunction,
|
||||
parameterListEnd);
|
||||
}
|
||||
|
||||
|
@ -743,7 +744,8 @@ frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
|
|||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::Generator, SyncFunction,
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::Generator,
|
||||
FunctionAsyncKind::SyncFunction,
|
||||
parameterListEnd);
|
||||
}
|
||||
|
||||
|
@ -756,7 +758,8 @@ frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fu
|
|||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::NotGenerator, AsyncFunction,
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::NotGenerator,
|
||||
FunctionAsyncKind::AsyncFunction,
|
||||
parameterListEnd);
|
||||
}
|
||||
|
||||
|
@ -769,6 +772,7 @@ frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction f
|
|||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::Generator, AsyncFunction,
|
||||
return compiler.compileStandaloneFunction(fun, GeneratorKind::Generator,
|
||||
FunctionAsyncKind::AsyncFunction,
|
||||
parameterListEnd);
|
||||
}
|
||||
|
|
|
@ -482,8 +482,6 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
|
|||
MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
|
||||
Handle<LexicalScope::Data*> bindings);
|
||||
MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
|
||||
MOZ_MUST_USE bool enterComprehensionFor(BytecodeEmitter* bce,
|
||||
Handle<LexicalScope::Data*> bindings);
|
||||
MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
|
||||
MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
|
||||
MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
|
||||
|
@ -981,36 +979,6 @@ BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBo
|
|||
return checkEnvironmentChainLength(bce);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce,
|
||||
Handle<LexicalScope::Data*> bindings)
|
||||
{
|
||||
if (!enterLexical(bce, ScopeKind::Lexical, bindings))
|
||||
return false;
|
||||
|
||||
// For comprehensions, initialize all lexical names up front to undefined
|
||||
// because they're now a dead feature and don't interact properly with
|
||||
// TDZ.
|
||||
auto nop = [](BytecodeEmitter*, const NameLocation&, bool) {
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!bce->emit1(JSOP_UNDEFINED))
|
||||
return false;
|
||||
|
||||
RootedAtom name(bce->cx);
|
||||
for (BindingIter bi(*bindings, frameSlotStart(), /* isNamedLambda = */ false); bi; bi++) {
|
||||
name = bi.name();
|
||||
if (!bce->emitInitializeName(name, nop))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce->emit1(JSOP_POP))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
|
||||
{
|
||||
|
@ -3168,13 +3136,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
*answer = true;
|
||||
return true;
|
||||
|
||||
// These unary cases have side effects on the enclosing object/array,
|
||||
// sure. But that's not the question this function answers: it's
|
||||
// whether the operation may have a side effect on something *other* than
|
||||
// the result of the overall operation in which it's embedded. The
|
||||
// answer to that is no, for an object literal having a mutated prototype
|
||||
// and an array comprehension containing no other effectful operations
|
||||
// only produce a value, without affecting anything else.
|
||||
// This unary case has side effects on the enclosing object, sure. But
|
||||
// that's not the question this function answers: it's whether the
|
||||
// operation may have a side effect on something *other* than the result
|
||||
// of the overall operation in which it's embedded. The answer to that
|
||||
// is no, because an object literal having a mutated prototype only
|
||||
// produces a value, without affecting anything else.
|
||||
case PNK_MUTATEPROTO:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
return checkSideEffects(pn->pn_kid, answer);
|
||||
|
|
|
@ -690,10 +690,6 @@ class FullParseHandler
|
|||
return node->isKind(PNK_YIELD) && !node->isInParens();
|
||||
}
|
||||
|
||||
bool isUnparenthesizedCommaExpression(ParseNode* node) {
|
||||
return node->isKind(PNK_COMMA) && !node->isInParens();
|
||||
}
|
||||
|
||||
bool isUnparenthesizedAssignment(Node node) {
|
||||
if (node->isKind(PNK_ASSIGN) && !node->isInParens()) {
|
||||
// PNK_ASSIGN is also (mis)used for things like |var name = expr;|.
|
||||
|
|
|
@ -447,28 +447,7 @@ class ParseContext : public Nestable<ParseContext>
|
|||
// between scopes. Only used when syntax parsing.
|
||||
PooledVectorPtr<AtomVector> closedOverBindingsForLazy_;
|
||||
|
||||
// Monotonically increasing id.
|
||||
uint32_t scriptId_;
|
||||
|
||||
// Set when compiling a function using Parser::standaloneFunctionBody via
|
||||
// the Function or Generator constructor.
|
||||
bool isStandaloneFunctionBody_;
|
||||
|
||||
// Set when encountering a super.property inside a method. We need to mark
|
||||
// the nearest super scope as needing a home object.
|
||||
bool superScopeNeedsHomeObject_;
|
||||
|
||||
public:
|
||||
// lastYieldOffset stores the offset of the last yield that was parsed.
|
||||
// NoYieldOffset is its initial value.
|
||||
static const uint32_t NoYieldOffset = UINT32_MAX;
|
||||
uint32_t lastYieldOffset;
|
||||
|
||||
// lastAwaitOffset stores the offset of the last await that was parsed.
|
||||
// NoAwaitOffset is its initial value.
|
||||
static const uint32_t NoAwaitOffset = UINT32_MAX;
|
||||
uint32_t lastAwaitOffset;
|
||||
|
||||
// All inner functions in this context. Only used when syntax parsing.
|
||||
Rooted<GCVector<JSFunction*, 8>> innerFunctionsForLazy;
|
||||
|
||||
|
@ -479,11 +458,27 @@ class ParseContext : public Nestable<ParseContext>
|
|||
// pointer may be nullptr.
|
||||
Directives* newDirectives;
|
||||
|
||||
// Set when parsing a function and it has 'return <expr>;'
|
||||
bool funHasReturnExpr;
|
||||
// lastYieldOffset stores the offset of the last yield that was parsed.
|
||||
// NoYieldOffset is its initial value.
|
||||
static const uint32_t NoYieldOffset = UINT32_MAX;
|
||||
uint32_t lastYieldOffset;
|
||||
|
||||
// Set when parsing a function and it has 'return;'
|
||||
bool funHasReturnVoid;
|
||||
// lastAwaitOffset stores the offset of the last await that was parsed.
|
||||
// NoAwaitOffset is its initial value.
|
||||
static const uint32_t NoAwaitOffset = UINT32_MAX;
|
||||
uint32_t lastAwaitOffset;
|
||||
|
||||
private:
|
||||
// Monotonically increasing id.
|
||||
uint32_t scriptId_;
|
||||
|
||||
// Set when compiling a function using Parser::standaloneFunctionBody via
|
||||
// the Function or Generator constructor.
|
||||
bool isStandaloneFunctionBody_;
|
||||
|
||||
// Set when encountering a super.property inside a method. We need to mark
|
||||
// the nearest super scope as needing a home object.
|
||||
bool superScopeNeedsHomeObject_;
|
||||
|
||||
public:
|
||||
inline ParseContext(JSContext* cx, ParseContext*& parent, SharedContext* sc, ErrorReporter& errorReporter,
|
||||
|
@ -501,15 +496,13 @@ class ParseContext : public Nestable<ParseContext>
|
|||
varScope_(nullptr),
|
||||
positionalFormalParameterNames_(cx->frontendCollectionPool()),
|
||||
closedOverBindingsForLazy_(cx->frontendCollectionPool()),
|
||||
scriptId_(usedNames.nextScriptId()),
|
||||
isStandaloneFunctionBody_(false),
|
||||
superScopeNeedsHomeObject_(false),
|
||||
lastYieldOffset(NoYieldOffset),
|
||||
lastAwaitOffset(NoAwaitOffset),
|
||||
innerFunctionsForLazy(cx, GCVector<JSFunction*, 8>(cx)),
|
||||
newDirectives(newDirectives),
|
||||
funHasReturnExpr(false),
|
||||
funHasReturnVoid(false)
|
||||
lastYieldOffset(NoYieldOffset),
|
||||
lastAwaitOffset(NoAwaitOffset),
|
||||
scriptId_(usedNames.nextScriptId()),
|
||||
isStandaloneFunctionBody_(false),
|
||||
superScopeNeedsHomeObject_(false)
|
||||
{
|
||||
if (isFunctionBox()) {
|
||||
if (functionBox()->function()->isNamedLambda())
|
||||
|
@ -646,7 +639,7 @@ class ParseContext : public Nestable<ParseContext>
|
|||
}
|
||||
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? AsyncFunction : SyncFunction;
|
||||
return isAsync() ? FunctionAsyncKind::AsyncFunction : FunctionAsyncKind::SyncFunction;
|
||||
}
|
||||
|
||||
bool isArrowFunction() const {
|
||||
|
|
|
@ -639,7 +639,7 @@ class ParseNode
|
|||
|
||||
bool functionIsHoisted() const {
|
||||
MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION);
|
||||
MOZ_ASSERT(isOp(JSOP_LAMBDA) || // lambda, genexpr
|
||||
MOZ_ASSERT(isOp(JSOP_LAMBDA) || // lambda
|
||||
isOp(JSOP_LAMBDA_ARROW) || // arrow function
|
||||
isOp(JSOP_DEFFUN) || // non-body-level function statement
|
||||
isOp(JSOP_NOP) || // body-level function stmt in global code
|
||||
|
|
|
@ -465,14 +465,13 @@ FunctionBox::FunctionBox(JSContext* cx, LifoAlloc& alloc, ObjectBox* traceListHe
|
|||
toStringStart(toStringStart),
|
||||
toStringEnd(0),
|
||||
length(0),
|
||||
generatorKind_(GeneratorKindAsBit(generatorKind)),
|
||||
asyncKindBits_(AsyncKindAsBits(asyncKind)),
|
||||
isGenerator_(generatorKind == GeneratorKind::Generator),
|
||||
isAsync_(asyncKind == FunctionAsyncKind::AsyncFunction),
|
||||
hasDestructuringArgs(false),
|
||||
hasParameterExprs(false),
|
||||
hasDirectEvalInParameterExpr(false),
|
||||
hasDuplicateParameters(false),
|
||||
useAsm(false),
|
||||
insideUseAsm(false),
|
||||
isAnnexB(false),
|
||||
wasEmitted(false),
|
||||
declaredArguments(false),
|
||||
|
@ -482,7 +481,13 @@ FunctionBox::FunctionBox(JSContext* cx, LifoAlloc& alloc, ObjectBox* traceListHe
|
|||
usesReturn(false),
|
||||
hasRest_(false),
|
||||
isExprBody_(false),
|
||||
funCxFlags()
|
||||
hasExtensibleScope_(false),
|
||||
argumentsHasLocalBinding_(false),
|
||||
definitelyNeedsArgsObj_(false),
|
||||
needsHomeObject_(false),
|
||||
isDerivedClassConstructor_(false),
|
||||
hasThisBinding_(false),
|
||||
hasInnerFunctions_(false)
|
||||
{
|
||||
// Functions created at parse time may be set singleton after parsing and
|
||||
// baked into JIT code, so they must be allocated tenured. They are held by
|
||||
|
@ -521,8 +526,7 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
|
|||
|
||||
JSFunction* fun = function();
|
||||
|
||||
// Arrow functions and generator expression lambdas don't have
|
||||
// their own `this` binding.
|
||||
// Arrow functions don't have their own `this` binding.
|
||||
if (fun->isArrow()) {
|
||||
allowNewTarget_ = sc->allowNewTarget();
|
||||
allowSuperProperty_ = sc->allowSuperProperty();
|
||||
|
@ -944,7 +948,8 @@ template <class ParseHandler, typename CharT>
|
|||
FunctionBox*
|
||||
Parser<ParseHandler, CharT>::newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
|
||||
Directives inheritedDirectives,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind)
|
||||
{
|
||||
MOZ_ASSERT(fun);
|
||||
|
||||
|
@ -2518,7 +2523,7 @@ GetYieldHandling(GeneratorKind generatorKind)
|
|||
static AwaitHandling
|
||||
GetAwaitHandling(FunctionAsyncKind asyncKind)
|
||||
{
|
||||
if (asyncKind == SyncFunction)
|
||||
if (asyncKind == FunctionAsyncKind::SyncFunction)
|
||||
return AwaitIsName;
|
||||
return AwaitIsKeyword;
|
||||
}
|
||||
|
@ -2539,7 +2544,7 @@ Parser<FullParseHandler, char16_t>::standaloneFunction(HandleFunction fun,
|
|||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (asyncKind == AsyncFunction) {
|
||||
if (asyncKind == FunctionAsyncKind::AsyncFunction) {
|
||||
MOZ_ASSERT(tt == TOK_ASYNC);
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
@ -2687,7 +2692,6 @@ Parser<ParseHandler, CharT>::functionBody(InHandling inHandling, YieldHandling y
|
|||
FunctionSyntaxKind kind, FunctionBodyType type)
|
||||
{
|
||||
MOZ_ASSERT(pc->isFunctionBox());
|
||||
MOZ_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid);
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t startYieldOffset = pc->lastYieldOffset;
|
||||
|
@ -2738,16 +2742,9 @@ Parser<ParseHandler, CharT>::functionBody(InHandling inHandling, YieldHandling y
|
|||
}
|
||||
}
|
||||
|
||||
switch (pc->generatorKind()) {
|
||||
case GeneratorKind::NotGenerator:
|
||||
MOZ_ASSERT_IF(!pc->isAsync(), pc->lastYieldOffset == startYieldOffset);
|
||||
break;
|
||||
|
||||
case GeneratorKind::Generator:
|
||||
MOZ_ASSERT(kind != Arrow);
|
||||
MOZ_ASSERT(type == StatementListBody);
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT_IF(!pc->isGenerator() && !pc->isAsync(), pc->lastYieldOffset == startYieldOffset);
|
||||
MOZ_ASSERT_IF(pc->isGenerator(), kind != Arrow);
|
||||
MOZ_ASSERT_IF(pc->isGenerator(), type == StatementListBody);
|
||||
|
||||
if (pc->needsDotGeneratorName()) {
|
||||
MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
|
||||
|
@ -2789,7 +2786,8 @@ ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
|
|||
#endif
|
||||
switch (kind) {
|
||||
case Expression:
|
||||
flags = (generatorKind == GeneratorKind::NotGenerator && asyncKind == SyncFunction
|
||||
flags = (generatorKind == GeneratorKind::NotGenerator &&
|
||||
asyncKind == FunctionAsyncKind::SyncFunction
|
||||
? JSFunction::INTERPRETED_LAMBDA
|
||||
: JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC);
|
||||
break;
|
||||
|
@ -2798,7 +2796,8 @@ ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
|
|||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||
break;
|
||||
case Method:
|
||||
flags = (generatorKind == GeneratorKind::NotGenerator && asyncKind == SyncFunction
|
||||
flags = (generatorKind == GeneratorKind::NotGenerator &&
|
||||
asyncKind == FunctionAsyncKind::SyncFunction
|
||||
? JSFunction::INTERPRETED_METHOD
|
||||
: JSFunction::INTERPRETED_METHOD_GENERATOR_OR_ASYNC);
|
||||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||
|
@ -2826,13 +2825,14 @@ ParserBase::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
|
|||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||
}
|
||||
#endif
|
||||
flags = (generatorKind == GeneratorKind::NotGenerator && asyncKind == SyncFunction
|
||||
flags = (generatorKind == GeneratorKind::NotGenerator &&
|
||||
asyncKind == FunctionAsyncKind::SyncFunction
|
||||
? JSFunction::INTERPRETED_NORMAL
|
||||
: JSFunction::INTERPRETED_GENERATOR_OR_ASYNC);
|
||||
}
|
||||
|
||||
// We store the async wrapper in a slot for later access.
|
||||
if (asyncKind == AsyncFunction)
|
||||
if (asyncKind == FunctionAsyncKind::AsyncFunction)
|
||||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||
|
||||
fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,
|
||||
|
@ -3363,7 +3363,9 @@ Parser<ParseHandler, CharT>::functionDefinition(Node pn, uint32_t toStringStart,
|
|||
}
|
||||
|
||||
RootedObject proto(context);
|
||||
if (generatorKind == GeneratorKind::Generator || asyncKind == AsyncFunction) {
|
||||
if (generatorKind == GeneratorKind::Generator ||
|
||||
asyncKind == FunctionAsyncKind::AsyncFunction)
|
||||
{
|
||||
// If we are off thread, the generator meta-objects have
|
||||
// already been created by js::StartOffThreadParseTask, so cx will not
|
||||
// be necessary.
|
||||
|
@ -3437,7 +3439,7 @@ Parser<FullParseHandler, char16_t>::trySyntaxParseInnerFunction(ParseNode* pn, H
|
|||
// pays off for lots of code.
|
||||
if (pn->isLikelyIIFE() &&
|
||||
generatorKind == GeneratorKind::NotGenerator &&
|
||||
asyncKind == SyncFunction)
|
||||
asyncKind == FunctionAsyncKind::SyncFunction)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -3628,7 +3630,8 @@ Parser<FullParseHandler, char16_t>::standaloneLazyFunction(HandleFunction fun,
|
|||
// is a not-async arrow, use TokenStream::Operand to keep
|
||||
// verifyConsistentModifier from complaining (we will use
|
||||
// TokenStream::Operand in functionArguments).
|
||||
TokenStream::Modifier modifier = (fun->isArrow() && asyncKind == SyncFunction)
|
||||
TokenStream::Modifier modifier = (fun->isArrow() &&
|
||||
asyncKind == FunctionAsyncKind::SyncFunction)
|
||||
? TokenStream::Operand : TokenStream::None;
|
||||
if (!tokenStream.peekTokenPos(&pn->pn_pos, modifier))
|
||||
return null();
|
||||
|
@ -3875,7 +3878,7 @@ Parser<ParseHandler, CharT>::functionStmt(uint32_t toStringStart, YieldHandling
|
|||
|
||||
kind = (!pc->sc()->strict() &&
|
||||
generatorKind == GeneratorKind::NotGenerator &&
|
||||
asyncKind == SyncFunction)
|
||||
asyncKind == FunctionAsyncKind::SyncFunction)
|
||||
? DeclarationKind::SloppyLexicalFunction
|
||||
: DeclarationKind::LexicalFunction;
|
||||
} else {
|
||||
|
@ -5742,7 +5745,8 @@ Parser<ParseHandler, CharT>::exportDefault(uint32_t begin)
|
|||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return exportDefaultFunctionDeclaration(begin, toStringStart, AsyncFunction);
|
||||
return exportDefaultFunctionDeclaration(begin, toStringStart,
|
||||
FunctionAsyncKind::AsyncFunction);
|
||||
}
|
||||
|
||||
tokenStream.ungetToken();
|
||||
|
@ -5798,7 +5802,8 @@ Parser<ParseHandler, CharT>::exportDeclaration()
|
|||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return exportFunctionDeclaration(begin, toStringStart, AsyncFunction);
|
||||
return exportFunctionDeclaration(begin, toStringStart,
|
||||
FunctionAsyncKind::AsyncFunction);
|
||||
}
|
||||
|
||||
error(JSMSG_DECLARATION_AFTER_EXPORT);
|
||||
|
@ -6550,13 +6555,11 @@ Parser<ParseHandler, CharT>::returnStatement(YieldHandling yieldHandling)
|
|||
case TOK_SEMI:
|
||||
case TOK_RC:
|
||||
exprNode = null();
|
||||
pc->funHasReturnVoid = true;
|
||||
break;
|
||||
default: {
|
||||
exprNode = expr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!exprNode)
|
||||
return null();
|
||||
pc->funHasReturnExpr = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7591,7 +7594,8 @@ Parser<ParseHandler, CharT>::statementListItem(YieldHandling yieldHandling,
|
|||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return functionStmt(toStringStart, yieldHandling, NameRequired, AsyncFunction);
|
||||
return functionStmt(toStringStart, yieldHandling, NameRequired,
|
||||
FunctionAsyncKind::AsyncFunction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8065,7 +8069,7 @@ Parser<ParseHandler, CharT>::assignExpr(InHandling inHandling, YieldHandling yie
|
|||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.ungetToken();
|
||||
|
||||
FunctionAsyncKind asyncKind = SyncFunction;
|
||||
FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction;
|
||||
|
||||
if (next == TOK_ASYNC) {
|
||||
tokenStream.consumeKnownToken(next, TokenStream::Operand);
|
||||
|
@ -8078,7 +8082,7 @@ Parser<ParseHandler, CharT>::assignExpr(InHandling inHandling, YieldHandling yie
|
|||
// async [no LineTerminator here] AsyncArrowBindingIdentifier ...
|
||||
// async [no LineTerminator here] ArrowFormalParameters ...
|
||||
if (TokenKindIsPossibleIdentifier(nextSameLine) || nextSameLine == TOK_LP)
|
||||
asyncKind = AsyncFunction;
|
||||
asyncKind = FunctionAsyncKind::AsyncFunction;
|
||||
else
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
|
@ -9608,8 +9612,8 @@ Parser<ParseHandler, CharT>::methodDefinition(uint32_t toStringStart, PropertyTy
|
|||
|
||||
FunctionAsyncKind asyncKind = (propType == PropertyType::AsyncMethod ||
|
||||
propType == PropertyType::AsyncGeneratorMethod)
|
||||
? AsyncFunction
|
||||
: SyncFunction;
|
||||
? FunctionAsyncKind::AsyncFunction
|
||||
: FunctionAsyncKind::SyncFunction;
|
||||
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
|
||||
|
||||
|
@ -9743,7 +9747,8 @@ Parser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
|
|||
if (nextSameLine == TOK_FUNCTION) {
|
||||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.consumeKnownToken(TOK_FUNCTION);
|
||||
return functionExpr(toStringStart, PredictUninvoked, AsyncFunction);
|
||||
return functionExpr(toStringStart, PredictUninvoked,
|
||||
FunctionAsyncKind::AsyncFunction);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -593,9 +593,9 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
*/
|
||||
Node functionStmt(uint32_t toStringStart,
|
||||
YieldHandling yieldHandling, DefaultHandling defaultHandling,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
|
||||
Node functionExpr(uint32_t toStringStart, InvokedPrediction invoked = PredictUninvoked,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
|
||||
|
||||
Node statementList(YieldHandling yieldHandling);
|
||||
Node statement(YieldHandling yieldHandling);
|
||||
|
@ -650,12 +650,12 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
bool checkLocalExportNames(Node node);
|
||||
Node exportClause(uint32_t begin);
|
||||
Node exportFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
|
||||
Node exportVariableStatement(uint32_t begin);
|
||||
Node exportClassDeclaration(uint32_t begin);
|
||||
Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind);
|
||||
Node exportDefaultFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
|
||||
FunctionAsyncKind asyncKind = SyncFunction);
|
||||
FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
|
||||
Node exportDefaultClassDeclaration(uint32_t begin);
|
||||
Node exportDefaultAssignExpr(uint32_t begin);
|
||||
Node exportDefault(uint32_t begin);
|
||||
|
|
|
@ -62,121 +62,6 @@ StatementKindIsUnlabeledBreakTarget(StatementKind kind)
|
|||
return StatementKindIsLoop(kind) || kind == StatementKind::Switch;
|
||||
}
|
||||
|
||||
// These flags apply to both global and function contexts.
|
||||
class AnyContextFlags
|
||||
{
|
||||
// This class's data is all private and so only visible to these friends.
|
||||
friend class SharedContext;
|
||||
|
||||
// True if "use strict"; appears in the body instead of being inherited.
|
||||
bool hasExplicitUseStrict:1;
|
||||
|
||||
// The (static) bindings of this script need to support dynamic name
|
||||
// read/write access. Here, 'dynamic' means dynamic dictionary lookup on
|
||||
// the scope chain for a dynamic set of keys. The primary examples are:
|
||||
// - direct eval
|
||||
// - function::
|
||||
// - with
|
||||
// since both effectively allow any name to be accessed. Non-examples are:
|
||||
// - upvars of nested functions
|
||||
// - function statement
|
||||
// since the set of assigned name is known dynamically.
|
||||
//
|
||||
// Note: access through the arguments object is not considered dynamic
|
||||
// binding access since it does not go through the normal name lookup
|
||||
// mechanism. This is debatable and could be changed (although care must be
|
||||
// taken not to turn off the whole 'arguments' optimization). To answer the
|
||||
// more general "is this argument aliased" question, script->needsArgsObj
|
||||
// should be tested (see JSScript::argIsAliased).
|
||||
bool bindingsAccessedDynamically:1;
|
||||
|
||||
// Whether this script, or any of its inner scripts contains a debugger
|
||||
// statement which could potentially read or write anywhere along the
|
||||
// scope chain.
|
||||
bool hasDebuggerStatement:1;
|
||||
|
||||
// A direct eval occurs in the body of the script.
|
||||
bool hasDirectEval:1;
|
||||
|
||||
public:
|
||||
AnyContextFlags()
|
||||
: hasExplicitUseStrict(false),
|
||||
bindingsAccessedDynamically(false),
|
||||
hasDebuggerStatement(false),
|
||||
hasDirectEval(false)
|
||||
{ }
|
||||
};
|
||||
|
||||
class FunctionContextFlags
|
||||
{
|
||||
// This class's data is all private and so only visible to these friends.
|
||||
friend class FunctionBox;
|
||||
|
||||
// This function does something that can extend the set of bindings in its
|
||||
// call objects --- it does a direct eval in non-strict code, or includes a
|
||||
// function statement (as opposed to a function definition).
|
||||
//
|
||||
// This flag is *not* inherited by enclosed or enclosing functions; it
|
||||
// applies only to the function in whose flags it appears.
|
||||
//
|
||||
bool hasExtensibleScope:1;
|
||||
|
||||
// Technically, every function has a binding named 'arguments'. Internally,
|
||||
// this binding is only added when 'arguments' is mentioned by the function
|
||||
// body. This flag indicates whether 'arguments' has been bound either
|
||||
// through implicit use:
|
||||
// function f() { return arguments }
|
||||
// or explicit redeclaration:
|
||||
// function f() { var arguments; return arguments }
|
||||
//
|
||||
// Note 1: overwritten arguments (function() { arguments = 3 }) will cause
|
||||
// this flag to be set but otherwise require no special handling:
|
||||
// 'arguments' is just a local variable and uses of 'arguments' will just
|
||||
// read the local's current slot which may have been assigned. The only
|
||||
// special semantics is that the initial value of 'arguments' is the
|
||||
// arguments object (not undefined, like normal locals).
|
||||
//
|
||||
// Note 2: if 'arguments' is bound as a formal parameter, there will be an
|
||||
// 'arguments' in Bindings, but, as the "LOCAL" in the name indicates, this
|
||||
// flag will not be set. This is because, as a formal, 'arguments' will
|
||||
// have no special semantics: the initial value is unconditionally the
|
||||
// actual argument (or undefined if nactual < nformal).
|
||||
//
|
||||
bool argumentsHasLocalBinding:1;
|
||||
|
||||
// In many cases where 'arguments' has a local binding (as described above)
|
||||
// we do not need to actually create an arguments object in the function
|
||||
// prologue: instead we can analyze how 'arguments' is used (using the
|
||||
// simple dataflow analysis in analyzeSSA) to determine that uses of
|
||||
// 'arguments' can just read from the stack frame directly. However, the
|
||||
// dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
|
||||
// be unsound in several cases. The frontend filters out such cases by
|
||||
// setting this flag which eagerly sets script->needsArgsObj to true.
|
||||
//
|
||||
bool definitelyNeedsArgsObj:1;
|
||||
|
||||
bool needsHomeObject:1;
|
||||
bool isDerivedClassConstructor:1;
|
||||
|
||||
// Whether this function has a .this binding. If true, we need to emit
|
||||
// JSOP_FUNCTIONTHIS in the prologue to initialize it.
|
||||
bool hasThisBinding:1;
|
||||
|
||||
// Whether this function has nested functions.
|
||||
bool hasInnerFunctions:1;
|
||||
|
||||
public:
|
||||
FunctionContextFlags()
|
||||
: hasExtensibleScope(false),
|
||||
argumentsHasLocalBinding(false),
|
||||
definitelyNeedsArgsObj(false),
|
||||
needsHomeObject(false),
|
||||
isDerivedClassConstructor(false),
|
||||
hasThisBinding(false),
|
||||
hasInnerFunctions(false)
|
||||
{ }
|
||||
};
|
||||
|
||||
// List of directives that may be encountered in a Directive Prologue (ES5 15.1).
|
||||
class Directives
|
||||
{
|
||||
|
@ -207,10 +92,9 @@ class Directives
|
|||
};
|
||||
|
||||
// The kind of this-binding for the current scope. Note that arrow functions
|
||||
// (and generator expression lambdas) have a lexical this-binding so their
|
||||
// ThisBinding is the same as the ThisBinding of their enclosing scope and can
|
||||
// be any value.
|
||||
enum class ThisBinding { Global, Function, Module };
|
||||
// have a lexical this-binding so their ThisBinding is the same as the
|
||||
// ThisBinding of their enclosing scope and can be any value.
|
||||
enum class ThisBinding : uint8_t { Global, Function, Module };
|
||||
|
||||
class GlobalSharedContext;
|
||||
class EvalSharedContext;
|
||||
|
@ -225,13 +109,9 @@ class SharedContext
|
|||
{
|
||||
public:
|
||||
JSContext* const context;
|
||||
AnyContextFlags anyCxFlags;
|
||||
bool strictScript;
|
||||
bool localStrict;
|
||||
bool extraWarnings;
|
||||
|
||||
protected:
|
||||
enum class Kind {
|
||||
enum class Kind : uint8_t {
|
||||
FunctionBox,
|
||||
Global,
|
||||
Eval,
|
||||
|
@ -242,11 +122,47 @@ class SharedContext
|
|||
|
||||
ThisBinding thisBinding_;
|
||||
|
||||
bool allowNewTarget_;
|
||||
bool allowSuperProperty_;
|
||||
bool allowSuperCall_;
|
||||
bool inWith_;
|
||||
bool needsThisTDZChecks_;
|
||||
public:
|
||||
bool strictScript:1;
|
||||
bool localStrict:1;
|
||||
bool extraWarnings:1;
|
||||
|
||||
protected:
|
||||
bool allowNewTarget_:1;
|
||||
bool allowSuperProperty_:1;
|
||||
bool allowSuperCall_:1;
|
||||
bool inWith_:1;
|
||||
bool needsThisTDZChecks_:1;
|
||||
|
||||
// True if "use strict"; appears in the body instead of being inherited.
|
||||
bool hasExplicitUseStrict_:1;
|
||||
|
||||
// The (static) bindings of this script need to support dynamic name
|
||||
// read/write access. Here, 'dynamic' means dynamic dictionary lookup on
|
||||
// the scope chain for a dynamic set of keys. The primary examples are:
|
||||
// - direct eval
|
||||
// - function::
|
||||
// - with
|
||||
// since both effectively allow any name to be accessed. Non-examples are:
|
||||
// - upvars of nested functions
|
||||
// - function statement
|
||||
// since the set of assigned name is known dynamically.
|
||||
//
|
||||
// Note: access through the arguments object is not considered dynamic
|
||||
// binding access since it does not go through the normal name lookup
|
||||
// mechanism. This is debatable and could be changed (although care must be
|
||||
// taken not to turn off the whole 'arguments' optimization). To answer the
|
||||
// more general "is this argument aliased" question, script->needsArgsObj
|
||||
// should be tested (see JSScript::argIsAliased).
|
||||
bool bindingsAccessedDynamically_:1;
|
||||
|
||||
// Whether this script, or any of its inner scripts contains a debugger
|
||||
// statement which could potentially read or write anywhere along the
|
||||
// scope chain.
|
||||
bool hasDebuggerStatement_:1;
|
||||
|
||||
// A direct eval occurs in the body of the script.
|
||||
bool hasDirectEval_:1;
|
||||
|
||||
void computeAllowSyntax(Scope* scope);
|
||||
void computeInWith(Scope* scope);
|
||||
|
@ -255,17 +171,20 @@ class SharedContext
|
|||
public:
|
||||
SharedContext(JSContext* cx, Kind kind, Directives directives, bool extraWarnings)
|
||||
: context(cx),
|
||||
anyCxFlags(),
|
||||
kind_(kind),
|
||||
thisBinding_(ThisBinding::Global),
|
||||
strictScript(directives.strict()),
|
||||
localStrict(false),
|
||||
extraWarnings(extraWarnings),
|
||||
kind_(kind),
|
||||
thisBinding_(ThisBinding::Global),
|
||||
allowNewTarget_(false),
|
||||
allowSuperProperty_(false),
|
||||
allowSuperCall_(false),
|
||||
inWith_(false),
|
||||
needsThisTDZChecks_(false)
|
||||
needsThisTDZChecks_(false),
|
||||
hasExplicitUseStrict_(false),
|
||||
bindingsAccessedDynamically_(false),
|
||||
hasDebuggerStatement_(false),
|
||||
hasDirectEval_(false)
|
||||
{ }
|
||||
|
||||
// If this is the outermost SharedContext, the Scope that encloses
|
||||
|
@ -289,15 +208,15 @@ class SharedContext
|
|||
bool inWith() const { return inWith_; }
|
||||
bool needsThisTDZChecks() const { return needsThisTDZChecks_; }
|
||||
|
||||
bool hasExplicitUseStrict() const { return anyCxFlags.hasExplicitUseStrict; }
|
||||
bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
|
||||
bool hasDebuggerStatement() const { return anyCxFlags.hasDebuggerStatement; }
|
||||
bool hasDirectEval() const { return anyCxFlags.hasDirectEval; }
|
||||
bool hasExplicitUseStrict() const { return hasExplicitUseStrict_; }
|
||||
bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
|
||||
bool hasDebuggerStatement() const { return hasDebuggerStatement_; }
|
||||
bool hasDirectEval() const { return hasDirectEval_; }
|
||||
|
||||
void setExplicitUseStrict() { anyCxFlags.hasExplicitUseStrict = true; }
|
||||
void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; }
|
||||
void setHasDebuggerStatement() { anyCxFlags.hasDebuggerStatement = true; }
|
||||
void setHasDirectEval() { anyCxFlags.hasDirectEval = true; }
|
||||
void setExplicitUseStrict() { hasExplicitUseStrict_ = true; }
|
||||
void setBindingsAccessedDynamically() { bindingsAccessedDynamically_ = true; }
|
||||
void setHasDebuggerStatement() { hasDebuggerStatement_ = true; }
|
||||
void setHasDirectEval() { hasDirectEval_ = true; }
|
||||
|
||||
inline bool allBindingsClosedOver();
|
||||
|
||||
|
@ -404,15 +323,13 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
uint32_t toStringEnd;
|
||||
uint16_t length;
|
||||
|
||||
uint8_t generatorKind_; /* The GeneratorKind of this function. */
|
||||
uint8_t asyncKindBits_; /* The FunctionAsyncKind of this function. */
|
||||
|
||||
bool isGenerator_:1; /* generator function or async generator */
|
||||
bool isAsync_:1; /* async function or async generator */
|
||||
bool hasDestructuringArgs:1; /* parameter list contains destructuring expression */
|
||||
bool hasParameterExprs:1; /* parameter list contains expressions */
|
||||
bool hasDirectEvalInParameterExpr:1; /* parameter list contains direct eval */
|
||||
bool hasDuplicateParameters:1; /* parameter list contains duplicate names */
|
||||
bool useAsm:1; /* see useAsmOrInsideUseAsm */
|
||||
bool insideUseAsm:1; /* see useAsmOrInsideUseAsm */
|
||||
bool isAnnexB:1; /* need to emit a synthesized Annex B assignment */
|
||||
bool wasEmitted:1; /* Bytecode has been emitted for this function. */
|
||||
|
||||
|
@ -427,7 +344,58 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
* body or expression closure:
|
||||
* function(x) x*x */
|
||||
|
||||
FunctionContextFlags funCxFlags;
|
||||
// This function does something that can extend the set of bindings in its
|
||||
// call objects --- it does a direct eval in non-strict code, or includes a
|
||||
// function statement (as opposed to a function definition).
|
||||
//
|
||||
// This flag is *not* inherited by enclosed or enclosing functions; it
|
||||
// applies only to the function in whose flags it appears.
|
||||
//
|
||||
bool hasExtensibleScope_:1;
|
||||
|
||||
// Technically, every function has a binding named 'arguments'. Internally,
|
||||
// this binding is only added when 'arguments' is mentioned by the function
|
||||
// body. This flag indicates whether 'arguments' has been bound either
|
||||
// through implicit use:
|
||||
// function f() { return arguments }
|
||||
// or explicit redeclaration:
|
||||
// function f() { var arguments; return arguments }
|
||||
//
|
||||
// Note 1: overwritten arguments (function() { arguments = 3 }) will cause
|
||||
// this flag to be set but otherwise require no special handling:
|
||||
// 'arguments' is just a local variable and uses of 'arguments' will just
|
||||
// read the local's current slot which may have been assigned. The only
|
||||
// special semantics is that the initial value of 'arguments' is the
|
||||
// arguments object (not undefined, like normal locals).
|
||||
//
|
||||
// Note 2: if 'arguments' is bound as a formal parameter, there will be an
|
||||
// 'arguments' in Bindings, but, as the "LOCAL" in the name indicates, this
|
||||
// flag will not be set. This is because, as a formal, 'arguments' will
|
||||
// have no special semantics: the initial value is unconditionally the
|
||||
// actual argument (or undefined if nactual < nformal).
|
||||
//
|
||||
bool argumentsHasLocalBinding_:1;
|
||||
|
||||
// In many cases where 'arguments' has a local binding (as described above)
|
||||
// we do not need to actually create an arguments object in the function
|
||||
// prologue: instead we can analyze how 'arguments' is used (using the
|
||||
// simple dataflow analysis in analyzeSSA) to determine that uses of
|
||||
// 'arguments' can just read from the stack frame directly. However, the
|
||||
// dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
|
||||
// be unsound in several cases. The frontend filters out such cases by
|
||||
// setting this flag which eagerly sets script->needsArgsObj to true.
|
||||
//
|
||||
bool definitelyNeedsArgsObj_:1;
|
||||
|
||||
bool needsHomeObject_:1;
|
||||
bool isDerivedClassConstructor_:1;
|
||||
|
||||
// Whether this function has a .this binding. If true, we need to emit
|
||||
// JSOP_FUNCTIONTHIS in the prologue to initialize it.
|
||||
bool hasThisBinding_:1;
|
||||
|
||||
// Whether this function has nested functions.
|
||||
bool hasInnerFunctions_:1;
|
||||
|
||||
FunctionBox(JSContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
|
||||
uint32_t toStringStart, Directives directives, bool extraWarnings,
|
||||
|
@ -486,9 +454,15 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
return usesArguments && usesApply && usesThis && !usesReturn;
|
||||
}
|
||||
|
||||
GeneratorKind generatorKind() const { return GeneratorKindFromBit(generatorKind_); }
|
||||
bool isGenerator() const { return generatorKind() == GeneratorKind::Generator; }
|
||||
FunctionAsyncKind asyncKind() const { return AsyncKindFromBits(asyncKindBits_); }
|
||||
bool isGenerator() const { return isGenerator_; }
|
||||
GeneratorKind generatorKind() const {
|
||||
return isGenerator() ? GeneratorKind::Generator : GeneratorKind::NotGenerator;
|
||||
}
|
||||
|
||||
bool isAsync() const { return isAsync_; }
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? FunctionAsyncKind::AsyncFunction : FunctionAsyncKind::SyncFunction;
|
||||
}
|
||||
|
||||
bool needsFinalYield() const {
|
||||
return isGenerator() || isAsync();
|
||||
|
@ -500,7 +474,6 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
return isGenerator();
|
||||
}
|
||||
|
||||
bool isAsync() const { return asyncKind() == AsyncFunction; }
|
||||
bool isArrow() const { return function()->isArrow(); }
|
||||
|
||||
bool hasRest() const { return hasRest_; }
|
||||
|
@ -513,24 +486,24 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
isExprBody_ = true;
|
||||
}
|
||||
|
||||
bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; }
|
||||
bool hasThisBinding() const { return funCxFlags.hasThisBinding; }
|
||||
bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
|
||||
bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
|
||||
bool needsHomeObject() const { return funCxFlags.needsHomeObject; }
|
||||
bool isDerivedClassConstructor() const { return funCxFlags.isDerivedClassConstructor; }
|
||||
bool hasInnerFunctions() const { return funCxFlags.hasInnerFunctions; }
|
||||
bool hasExtensibleScope() const { return hasExtensibleScope_; }
|
||||
bool hasThisBinding() const { return hasThisBinding_; }
|
||||
bool argumentsHasLocalBinding() const { return argumentsHasLocalBinding_; }
|
||||
bool definitelyNeedsArgsObj() const { return definitelyNeedsArgsObj_; }
|
||||
bool needsHomeObject() const { return needsHomeObject_; }
|
||||
bool isDerivedClassConstructor() const { return isDerivedClassConstructor_; }
|
||||
bool hasInnerFunctions() const { return hasInnerFunctions_; }
|
||||
|
||||
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
|
||||
void setHasThisBinding() { funCxFlags.hasThisBinding = true; }
|
||||
void setArgumentsHasLocalBinding() { funCxFlags.argumentsHasLocalBinding = true; }
|
||||
void setDefinitelyNeedsArgsObj() { MOZ_ASSERT(funCxFlags.argumentsHasLocalBinding);
|
||||
funCxFlags.definitelyNeedsArgsObj = true; }
|
||||
void setHasExtensibleScope() { hasExtensibleScope_ = true; }
|
||||
void setHasThisBinding() { hasThisBinding_ = true; }
|
||||
void setArgumentsHasLocalBinding() { argumentsHasLocalBinding_ = true; }
|
||||
void setDefinitelyNeedsArgsObj() { MOZ_ASSERT(argumentsHasLocalBinding_);
|
||||
definitelyNeedsArgsObj_ = true; }
|
||||
void setNeedsHomeObject() { MOZ_ASSERT(function()->allowSuperProperty());
|
||||
funCxFlags.needsHomeObject = true; }
|
||||
needsHomeObject_ = true; }
|
||||
void setDerivedClassConstructor() { MOZ_ASSERT(function()->isClassConstructor());
|
||||
funCxFlags.isDerivedClassConstructor = true; }
|
||||
void setHasInnerFunctions() { funCxFlags.hasInnerFunctions = true; }
|
||||
isDerivedClassConstructor_ = true; }
|
||||
void setHasInnerFunctions() { hasInnerFunctions_ = true; }
|
||||
|
||||
bool hasSimpleParameterList() const {
|
||||
return !hasRest() && !hasParameterExprs && !hasDestructuringArgs;
|
||||
|
@ -546,7 +519,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
// certain parsing features that are necessary in general, but unnecessary
|
||||
// for validated asm.js.
|
||||
bool useAsmOrInsideUseAsm() const {
|
||||
return useAsm || insideUseAsm;
|
||||
return useAsm;
|
||||
}
|
||||
|
||||
void setStart(const TokenStream& tokenStream) {
|
||||
|
|
|
@ -113,14 +113,6 @@ class SyntaxParseHandler
|
|||
// |("use strict");| as a useless statement.
|
||||
NodeUnparenthesizedString,
|
||||
|
||||
// Legacy generator expressions of the form |(expr for (...))| and
|
||||
// array comprehensions of the form |[expr for (...)]|) don't permit
|
||||
// |expr| to be a comma expression. Thus we need this to treat
|
||||
// |(a(), b for (x in []))| as a syntax error and
|
||||
// |((a(), b) for (x in []))| as a generator that calls |a| and then
|
||||
// yields |b| each time it's resumed.
|
||||
NodeUnparenthesizedCommaExpr,
|
||||
|
||||
// Assignment expressions in condition contexts could be typos for
|
||||
// equality checks. (Think |if (x = y)| versus |if (x == y)|.) Thus
|
||||
// we need this to treat |if (x = y)| as a possible typo and
|
||||
|
@ -434,14 +426,13 @@ class SyntaxParseHandler
|
|||
}
|
||||
|
||||
Node newCommaExpressionList(Node kid) {
|
||||
return NodeUnparenthesizedCommaExpr;
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
void addList(Node list, Node kid) {
|
||||
MOZ_ASSERT(list == NodeGeneric ||
|
||||
list == NodeUnparenthesizedArray ||
|
||||
list == NodeUnparenthesizedObject ||
|
||||
list == NodeUnparenthesizedCommaExpr ||
|
||||
list == NodeVarDeclaration ||
|
||||
list == NodeLexicalDeclaration ||
|
||||
list == NodeFunctionCall);
|
||||
|
@ -455,10 +446,6 @@ class SyntaxParseHandler
|
|||
return kind == PNK_ASSIGN ? NodeUnparenthesizedAssignment : NodeGeneric;
|
||||
}
|
||||
|
||||
bool isUnparenthesizedCommaExpression(Node node) {
|
||||
return node == NodeUnparenthesizedCommaExpr;
|
||||
}
|
||||
|
||||
bool isUnparenthesizedAssignment(Node node) {
|
||||
return node == NodeUnparenthesizedAssignment;
|
||||
}
|
||||
|
@ -503,7 +490,6 @@ class SyntaxParseHandler
|
|||
// Other nodes need not be recognizable after parenthesization; convert
|
||||
// them to a generic node.
|
||||
if (node == NodeUnparenthesizedString ||
|
||||
node == NodeUnparenthesizedCommaExpr ||
|
||||
node == NodeUnparenthesizedAssignment ||
|
||||
node == NodeUnparenthesizedUnary)
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "builtin/ModuleObject.h"
|
||||
|
@ -1754,6 +1755,15 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
|
|||
traverseEdge(obj, v.toString());
|
||||
} else if (v.isObject()) {
|
||||
JSObject* obj2 = &v.toObject();
|
||||
#ifdef DEBUG
|
||||
if (!obj2) {
|
||||
fprintf(stderr,
|
||||
"processMarkStackTop found ObjectValue(nullptr) "
|
||||
"at %zu Values from end of array in object:\n",
|
||||
end - (vp - 1));
|
||||
DumpObject(obj);
|
||||
}
|
||||
#endif
|
||||
CheckForCompartmentMismatch(obj, obj2);
|
||||
if (mark(obj2)) {
|
||||
// Save the rest of this value array for later and start scanning obj2's children.
|
||||
|
|
|
@ -367,7 +367,7 @@ def main(argv):
|
|||
try:
|
||||
ok = None
|
||||
if options.remote:
|
||||
ok = jittests.run_tests_remote(job_list, job_count, prefix, options)
|
||||
ok = jittests.run_tests(job_list, job_count, prefix, options, remote=True)
|
||||
else:
|
||||
with change_env(test_environment):
|
||||
ok = jittests.run_tests(job_list, job_count, prefix, options)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// |jit-test| error:TypeError
|
||||
"use strict";
|
||||
|
||||
// Make it impossible to create a toSource() representation of |o|, because
|
||||
// 100 * 2**22 exceeds the maximum string length.
|
||||
var s = "a".repeat(2 ** 22);
|
||||
var o = {};
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
o["$" + i] = s;
|
||||
}
|
||||
|
||||
Object.seal(o);
|
||||
|
||||
// Before the patch the toSource() represention was generated when an
|
||||
// assignment failed in strict mode. And because it's not possible to create
|
||||
// a toSource() representation for |o| (see above), this line caused an
|
||||
// InternalError to be thrown. With the patch this line throws a TypeError.
|
||||
o.foo = 0;
|
|
@ -0,0 +1,12 @@
|
|||
// https://tc39.github.io/proposal-async-iteration
|
||||
|
||||
// Recursion between:
|
||||
// 11.4.3.3 AsyncGeneratorResolve, step 8
|
||||
// 11.4.3.5 AsyncGeneratorResumeNext, step 11.
|
||||
|
||||
var asyncIter = async function*(){ yield; }();
|
||||
asyncIter.next();
|
||||
|
||||
for (var i = 0; i < 20000; i++) {
|
||||
asyncIter.next();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// https://tc39.github.io/proposal-async-iteration
|
||||
|
||||
// Recursion between:
|
||||
// 11.4.3.4 AsyncGeneratorReject, step 7.
|
||||
// 11.4.3.5 AsyncGeneratorResumeNext, step 10.b.ii.2.
|
||||
|
||||
var asyncIter = async function*(){ yield; }();
|
||||
asyncIter.next();
|
||||
|
||||
for (var i = 0; i < 20000; i++) {
|
||||
asyncIter.throw();
|
||||
}
|
|
@ -9,7 +9,7 @@ var cases = [
|
|||
"var x = VAL; @@",
|
||||
"Object.prototype.x = VAL; @@",
|
||||
|
||||
// let, catch, and comprehension bindings
|
||||
// let and catch bindings
|
||||
"let x = VAL; @@",
|
||||
"{ let x = VAL; @@ }",
|
||||
"try { throw VAL; } catch (x) { @@ }",
|
||||
|
|
|
@ -12,7 +12,7 @@ function unlikelyToHang(code) {
|
|||
return true && code.indexOf("infloop") == -1 && !(codeL.match(/const.*for/)) // can be an infinite loop: function() { const x = 1; for(x in ({a1:1})) dumpln(3); }
|
||||
&& !(codeL.match(/for.*const/)) // can be an infinite loop: for (x in ...); const x;
|
||||
&& !(codeL.match(/for.*in.*uneval/)) // can be slow to loop through the huge string uneval(this), for example
|
||||
&& !(codeL.match(/for.*for.*for/)) // nested for loops (including for..in, array comprehensions, etc) can take a while
|
||||
&& !(codeL.match(/for.*for.*for/)) // nested for loops (including for..in, etc) can take a while
|
||||
&& !(codeL.match(/for.*for.*gc/))
|
||||
}
|
||||
function whatToTestSpidermonkeyTrunk(code) {
|
||||
|
|
|
@ -229,7 +229,7 @@ jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame,
|
|||
bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
|
||||
|
||||
rfe->kind = ResumeFromException::RESUME_BAILOUT;
|
||||
rfe->target = cx->runtime()->jitRuntime()->getBailoutTail()->raw();
|
||||
rfe->target = cx->runtime()->jitRuntime()->getBailoutTail().value;
|
||||
rfe->bailoutInfo = bailoutInfo;
|
||||
} else {
|
||||
// Bailout failed. If the overrecursion check failed, clear the
|
||||
|
|
|
@ -1503,7 +1503,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
|||
|
||||
// Push return address into the ArgumentsRectifier code, immediately after the ioncode
|
||||
// call.
|
||||
void* rectReturnAddr = cx->runtime()->jitRuntime()->getArgumentsRectifierReturnAddr();
|
||||
void* rectReturnAddr = cx->runtime()->jitRuntime()->getArgumentsRectifierReturnAddr().value;
|
||||
MOZ_ASSERT(rectReturnAddr);
|
||||
if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
|
||||
return false;
|
||||
|
|
|
@ -149,7 +149,7 @@ BaselineCacheIRCompiler::callVM(MacroAssembler& masm, const VMFunction& fun)
|
|||
{
|
||||
MOZ_ASSERT(inStubFrame_);
|
||||
|
||||
uint8_t* code = cx_->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
TrampolinePtr code = cx_->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
MOZ_ASSERT(fun.expectTailCall == NonTailCall);
|
||||
MOZ_ASSERT(engine_ == ICStubEngine::Baseline);
|
||||
|
||||
|
@ -652,9 +652,8 @@ BaselineCacheIRCompiler::emitCallScriptedGetterResult()
|
|||
masm.branch32(Assembler::Equal, callee, Imm32(0), &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
JitCode* argumentsRectifier = cx_->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
|
||||
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
|
||||
TrampolinePtr argumentsRectifier = cx_->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, code);
|
||||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
@ -1763,9 +1762,8 @@ BaselineCacheIRCompiler::emitCallScriptedSetter()
|
|||
masm.branch32(Assembler::BelowOrEqual, scratch2, Imm32(1), &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
JitCode* argumentsRectifier = cx_->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), scratch1);
|
||||
masm.loadPtr(Address(scratch1, JitCode::offsetOfCode()), scratch1);
|
||||
TrampolinePtr argumentsRectifier = cx_->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, scratch1);
|
||||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
|
|
@ -4867,7 +4867,7 @@ BaselineCompiler::emit_JSOP_RESUME()
|
|||
pushArg(genObj);
|
||||
pushArg(scratch2);
|
||||
|
||||
uint8_t* code = cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowInfo);
|
||||
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowInfo);
|
||||
|
||||
// Create the frame descriptor.
|
||||
masm.subStackPtrFrom(scratch1);
|
||||
|
@ -4882,7 +4882,7 @@ BaselineCompiler::emit_JSOP_RESUME()
|
|||
#ifndef JS_CODEGEN_ARM64
|
||||
masm.push(ImmWord(0));
|
||||
#endif
|
||||
masm.jump(ImmPtr(code));
|
||||
masm.jump(code);
|
||||
}
|
||||
|
||||
// If the generator script has no JIT code, call into the VM.
|
||||
|
|
|
@ -3267,11 +3267,8 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
JitCode* argumentsRectifier =
|
||||
cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
|
||||
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
|
||||
TrampolinePtr argumentsRectifier = cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, code);
|
||||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
@ -3759,11 +3756,8 @@ ICCall_ScriptedApplyArray::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
JitCode* argumentsRectifier =
|
||||
cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
|
||||
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
|
||||
TrampolinePtr argumentsRectifier = cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, target);
|
||||
}
|
||||
masm.bind(&noUnderflow);
|
||||
regs.add(argcReg);
|
||||
|
@ -3852,11 +3846,8 @@ ICCall_ScriptedApplyArguments::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
JitCode* argumentsRectifier =
|
||||
cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), target);
|
||||
masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
|
||||
TrampolinePtr argumentsRectifier = cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, target);
|
||||
}
|
||||
masm.bind(&noUnderflow);
|
||||
regs.add(argcReg);
|
||||
|
@ -3976,11 +3967,8 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
|
||||
{
|
||||
// Call the arguments rectifier.
|
||||
JitCode* argumentsRectifier =
|
||||
cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), code);
|
||||
masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
|
||||
TrampolinePtr argumentsRectifier = cx->runtime()->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, code);
|
||||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
|
|
@ -4253,9 +4253,6 @@ CodeGenerator::visitCallGeneric(LCallGeneric* call)
|
|||
// Known-target case is handled by LCallKnown.
|
||||
MOZ_ASSERT(!call->hasSingleTarget());
|
||||
|
||||
// Generate an ArgumentsRectifier.
|
||||
JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.checkStackAlignment();
|
||||
|
||||
// Guard that calleereg is actually a function object.
|
||||
|
@ -4298,8 +4295,8 @@ CodeGenerator::visitCallGeneric(LCallGeneric* call)
|
|||
// Argument fixed needed. Load the ArgumentsRectifier.
|
||||
masm.bind(&thunk);
|
||||
{
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
|
||||
masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
|
||||
TrampolinePtr argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, objreg);
|
||||
}
|
||||
|
||||
// Finally call the function in objreg.
|
||||
|
@ -4727,10 +4724,8 @@ CodeGenerator::emitApplyGeneric(T* apply)
|
|||
masm.bind(&underflow);
|
||||
|
||||
// Hardcode the address of the argumentsRectifier code.
|
||||
JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
|
||||
|
||||
masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
|
||||
masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
|
||||
TrampolinePtr argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
|
||||
masm.movePtr(argumentsRectifier, objreg);
|
||||
}
|
||||
|
||||
masm.bind(&rejoin);
|
||||
|
@ -7951,14 +7946,14 @@ JitCompartment::generateStringConcatStub(JSContext* cx)
|
|||
return code;
|
||||
}
|
||||
|
||||
JitCode*
|
||||
JitRuntime::generateMallocStub(JSContext* cx)
|
||||
void
|
||||
JitRuntime::generateMallocStub(MacroAssembler& masm)
|
||||
{
|
||||
const Register regReturn = CallTempReg0;
|
||||
const Register regZone = CallTempReg0;
|
||||
const Register regNBytes = CallTempReg1;
|
||||
|
||||
MacroAssembler masm(cx);
|
||||
mallocStubOffset_ = startTrampolineCode(masm);
|
||||
|
||||
AllocatableRegisterSet regs(RegisterSet::Volatile());
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
|
@ -7980,27 +7975,15 @@ JitRuntime::generateMallocStub(JSContext* cx)
|
|||
|
||||
masm.PopRegsInMask(save);
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("MallocStub");
|
||||
JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(code, "MallocStub");
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
vtune::MarkStub(code, "MallocStub");
|
||||
#endif
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
JitCode*
|
||||
JitRuntime::generateFreeStub(JSContext* cx)
|
||||
void
|
||||
JitRuntime::generateFreeStub(MacroAssembler& masm)
|
||||
{
|
||||
const Register regSlots = CallTempReg0;
|
||||
|
||||
MacroAssembler masm(cx);
|
||||
freeStubOffset_ = startTrampolineCode(masm);
|
||||
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
masm.pushReturnAddress();
|
||||
#endif
|
||||
|
@ -8020,26 +8003,13 @@ JitRuntime::generateFreeStub(JSContext* cx)
|
|||
masm.PopRegsInMask(save);
|
||||
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("FreeStub");
|
||||
JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(code, "FreeStub");
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
vtune::MarkStub(code, "FreeStub");
|
||||
#endif
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
JitCode*
|
||||
JitRuntime::generateLazyLinkStub(JSContext* cx)
|
||||
void
|
||||
JitRuntime::generateLazyLinkStub(MacroAssembler& masm)
|
||||
{
|
||||
MacroAssembler masm(cx);
|
||||
lazyLinkStubOffset_ = startTrampolineCode(masm);
|
||||
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
masm.pushReturnAddress();
|
||||
#endif
|
||||
|
@ -8049,14 +8019,13 @@ JitRuntime::generateLazyLinkStub(JSContext* cx)
|
|||
|
||||
masm.loadJSContext(temp0);
|
||||
masm.enterFakeExitFrame(temp0, temp0, ExitFrameType::LazyLink);
|
||||
masm.PushStubCode();
|
||||
|
||||
masm.setupUnalignedABICall(temp0);
|
||||
masm.passABIArg(temp0);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, LazyLinkTopActivation), MoveOp::GENERAL,
|
||||
CheckUnsafeCallWithABI::DontCheckHasExitFrame);
|
||||
|
||||
masm.leaveExitFrame(/* stub code */ sizeof(JitCode*));
|
||||
masm.leaveExitFrame();
|
||||
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
// Restore the return address such that the emitPrologue function of the
|
||||
|
@ -8065,17 +8034,7 @@ JitRuntime::generateLazyLinkStub(JSContext* cx)
|
|||
#endif
|
||||
masm.jump(ReturnReg);
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("LazyLinkStub");
|
||||
JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(code, "LazyLinkStub");
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
vtune::MarkStub(code, "LazyLinkStub");
|
||||
#endif
|
||||
return code;
|
||||
lazyLinkStubEndOffset_ = masm.currentOffset();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -9563,11 +9522,8 @@ CodeGenerator::generate()
|
|||
// creating the actual frame.
|
||||
generateArgumentsChecks();
|
||||
|
||||
if (frameClass_ != FrameSizeClass::None()) {
|
||||
deoptTable_ = gen->jitRuntime()->getBailoutTable(frameClass_);
|
||||
if (!deoptTable_)
|
||||
return false;
|
||||
}
|
||||
if (frameClass_ != FrameSizeClass::None())
|
||||
deoptTable_.emplace(gen->jitRuntime()->getBailoutTable(frameClass_));
|
||||
|
||||
// Skip over the alternative entry to IonScript code.
|
||||
Label skipPrologue;
|
||||
|
@ -9935,8 +9891,6 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
|
|||
ionScript->setOsrEntryOffset(getOsrEntryOffset());
|
||||
ionScript->setInvalidationEpilogueOffset(invalidate_.offset());
|
||||
|
||||
ionScript->setDeoptTable(deoptTable_);
|
||||
|
||||
#if defined(JS_ION_PERF)
|
||||
if (PerfEnabled())
|
||||
perfSpewer_.writeProfile(script, code, masm);
|
||||
|
|
|
@ -194,17 +194,17 @@ jit::InitializeIon()
|
|||
JitRuntime::JitRuntime(JSRuntime* rt)
|
||||
: execAlloc_(rt),
|
||||
backedgeExecAlloc_(rt),
|
||||
exceptionTail_(nullptr),
|
||||
bailoutTail_(nullptr),
|
||||
profilerExitFrameTail_(nullptr),
|
||||
enterJIT_(nullptr),
|
||||
bailoutHandler_(nullptr),
|
||||
argumentsRectifier_(nullptr),
|
||||
argumentsRectifierReturnAddr_(nullptr),
|
||||
invalidator_(nullptr),
|
||||
exceptionTailOffset_(0),
|
||||
bailoutTailOffset_(0),
|
||||
profilerExitFrameTailOffset_(0),
|
||||
enterJITOffset_(0),
|
||||
bailoutHandlerOffset_(0),
|
||||
argumentsRectifierOffset_(0),
|
||||
argumentsRectifierReturnOffset_(0),
|
||||
invalidatorOffset_(0),
|
||||
debugTrapHandler_(nullptr),
|
||||
baselineDebugModeOSRHandler_(nullptr),
|
||||
functionWrapperCode_(nullptr),
|
||||
trampolineCode_(nullptr),
|
||||
functionWrappers_(nullptr),
|
||||
preventBackedgePatching_(false),
|
||||
jitcodeGlobalTable_(nullptr)
|
||||
|
@ -220,6 +220,15 @@ JitRuntime::~JitRuntime()
|
|||
js_delete(jitcodeGlobalTable_.ref());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
JitRuntime::startTrampolineCode(MacroAssembler& masm)
|
||||
{
|
||||
masm.assumeUnreachable("Shouldn't get here");
|
||||
masm.flushBuffer();
|
||||
masm.haltingAlign(CodeAlignment);
|
||||
return masm.currentOffset();
|
||||
}
|
||||
|
||||
bool
|
||||
JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
|
@ -234,23 +243,11 @@ JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
|
|||
if (!functionWrappers_ || !functionWrappers_->init())
|
||||
return false;
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting profiler exit frame tail stub");
|
||||
profilerExitFrameTail_ = generateProfilerExitFrameTailStub(cx);
|
||||
if (!profilerExitFrameTail_)
|
||||
return false;
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
|
||||
|
||||
void* handler = JS_FUNC_TO_DATA_PTR(void*, jit::HandleException);
|
||||
|
||||
exceptionTail_ = generateExceptionTailStub(cx, handler);
|
||||
if (!exceptionTail_)
|
||||
return false;
|
||||
MacroAssembler masm;
|
||||
|
||||
Label bailoutTail;
|
||||
JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub");
|
||||
bailoutTail_ = generateBailoutTailStub(cx);
|
||||
if (!bailoutTail_)
|
||||
return false;
|
||||
generateBailoutTailStub(masm, &bailoutTail);
|
||||
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
JitSpew(JitSpew_Codegen, "# Emitting bailout tables");
|
||||
|
@ -264,22 +261,15 @@ JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
|
|||
FrameSizeClass class_ = FrameSizeClass::FromClass(id);
|
||||
if (class_ == FrameSizeClass::ClassLimit())
|
||||
break;
|
||||
bailoutTables.infallibleAppend((JitCode*)nullptr);
|
||||
JitSpew(JitSpew_Codegen, "# Bailout table");
|
||||
bailoutTables[id] = generateBailoutTable(cx, id);
|
||||
if (!bailoutTables[id])
|
||||
return false;
|
||||
bailoutTables.infallibleAppend(generateBailoutTable(masm, &bailoutTail, id));
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting bailout handler");
|
||||
bailoutHandler_ = generateBailoutHandler(cx);
|
||||
if (!bailoutHandler_)
|
||||
return false;
|
||||
generateBailoutHandler(masm, &bailoutTail);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting invalidator");
|
||||
invalidator_ = generateInvalidator(cx);
|
||||
if (!invalidator_)
|
||||
return false;
|
||||
generateInvalidator(masm, &bailoutTail);
|
||||
}
|
||||
|
||||
// The arguments rectifier has to use the same frame layout as the function
|
||||
|
@ -292,82 +282,67 @@ JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock)
|
|||
"thus a rectifier frame can be used with a wasm frame");
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting sequential arguments rectifier");
|
||||
argumentsRectifier_ = generateArgumentsRectifier(cx, &argumentsRectifierReturnAddr_.writeRef());
|
||||
if (!argumentsRectifier_)
|
||||
return false;
|
||||
generateArgumentsRectifier(masm);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting EnterJIT sequence");
|
||||
enterJIT_ = generateEnterJIT(cx);
|
||||
if (!enterJIT_)
|
||||
return false;
|
||||
generateEnterJIT(cx, masm);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Value");
|
||||
valuePreBarrier_ = generatePreBarrier(cx, MIRType::Value);
|
||||
if (!valuePreBarrier_)
|
||||
return false;
|
||||
valuePreBarrierOffset_ = generatePreBarrier(cx, masm, MIRType::Value);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for String");
|
||||
stringPreBarrier_ = generatePreBarrier(cx, MIRType::String);
|
||||
if (!stringPreBarrier_)
|
||||
return false;
|
||||
stringPreBarrierOffset_ = generatePreBarrier(cx, masm, MIRType::String);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Object");
|
||||
objectPreBarrier_ = generatePreBarrier(cx, MIRType::Object);
|
||||
if (!objectPreBarrier_)
|
||||
return false;
|
||||
objectPreBarrierOffset_ = generatePreBarrier(cx, masm, MIRType::Object);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Shape");
|
||||
shapePreBarrier_ = generatePreBarrier(cx, MIRType::Shape);
|
||||
if (!shapePreBarrier_)
|
||||
return false;
|
||||
shapePreBarrierOffset_ = generatePreBarrier(cx, masm, MIRType::Shape);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for ObjectGroup");
|
||||
objectGroupPreBarrier_ = generatePreBarrier(cx, MIRType::ObjectGroup);
|
||||
if (!objectGroupPreBarrier_)
|
||||
return false;
|
||||
objectGroupPreBarrierOffset_ = generatePreBarrier(cx, masm, MIRType::ObjectGroup);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting malloc stub");
|
||||
mallocStub_ = generateMallocStub(cx);
|
||||
if (!mallocStub_)
|
||||
return false;
|
||||
generateMallocStub(masm);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting free stub");
|
||||
freeStub_ = generateFreeStub(cx);
|
||||
if (!freeStub_)
|
||||
return false;
|
||||
|
||||
{
|
||||
JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
|
||||
MacroAssembler masm;
|
||||
for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
|
||||
if (functionWrappers_->has(fun)) {
|
||||
// Duplicate VMFunction definition. See VMFunction::hash.
|
||||
continue;
|
||||
}
|
||||
JitSpew(JitSpew_Codegen, "# VM function wrapper");
|
||||
if (!generateVMWrapper(cx, masm, *fun))
|
||||
return false;
|
||||
}
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("VMWrappers");
|
||||
functionWrapperCode_ = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||
if (!functionWrapperCode_)
|
||||
return false;
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(functionWrapperCode_, "VMWrappers");
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
vtune::MarkStub(functionWrapperCode_, "VMWrappers");
|
||||
#endif
|
||||
}
|
||||
generateFreeStub(masm);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting lazy link stub");
|
||||
lazyLinkStub_ = generateLazyLinkStub(cx);
|
||||
if (!lazyLinkStub_)
|
||||
generateLazyLinkStub(masm);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting VM function wrappers");
|
||||
for (VMFunction* fun = VMFunction::functions; fun; fun = fun->next) {
|
||||
if (functionWrappers_->has(fun)) {
|
||||
// Duplicate VMFunction definition. See VMFunction::hash.
|
||||
continue;
|
||||
}
|
||||
JitSpew(JitSpew_Codegen, "# VM function wrapper");
|
||||
if (!generateVMWrapper(cx, masm, *fun))
|
||||
return false;
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting profiler exit frame tail stub");
|
||||
Label profilerExitTail;
|
||||
generateProfilerExitFrameTailStub(masm, &profilerExitTail);
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
|
||||
void* handler = JS_FUNC_TO_DATA_PTR(void*, jit::HandleException);
|
||||
generateExceptionTailStub(masm, handler, &profilerExitTail);
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("Trampolines");
|
||||
trampolineCode_ = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||
if (!trampolineCode_)
|
||||
return false;
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(trampolineCode_, "Trampolines");
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
vtune::MarkStub(trampolineCode_, "Trampolines");
|
||||
#endif
|
||||
|
||||
jitcodeGlobalTable_ = cx->new_<JitcodeGlobalTable>();
|
||||
if (!jitcodeGlobalTable_)
|
||||
return false;
|
||||
|
@ -733,27 +708,30 @@ JitZone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
|||
*cachedCFG += cfgSpace_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
JitCode*
|
||||
TrampolinePtr
|
||||
JitRuntime::getBailoutTable(const FrameSizeClass& frameClass) const
|
||||
{
|
||||
MOZ_ASSERT(frameClass != FrameSizeClass::None());
|
||||
return bailoutTables_.ref()[frameClass.classId()];
|
||||
return trampolineCode(bailoutTables_.ref()[frameClass.classId()].startOffset);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
uint32_t
|
||||
JitRuntime::getBailoutTableSize(const FrameSizeClass& frameClass) const
|
||||
{
|
||||
MOZ_ASSERT(frameClass != FrameSizeClass::None());
|
||||
return bailoutTables_.ref()[frameClass.classId()].size;
|
||||
}
|
||||
|
||||
TrampolinePtr
|
||||
JitRuntime::getVMWrapper(const VMFunction& f) const
|
||||
{
|
||||
MOZ_ASSERT(functionWrappers_);
|
||||
MOZ_ASSERT(functionWrappers_->initialized());
|
||||
MOZ_ASSERT(functionWrapperCode_);
|
||||
MOZ_ASSERT(trampolineCode_);
|
||||
|
||||
JitRuntime::VMWrapperMap::Ptr p = functionWrappers_->readonlyThreadsafeLookup(&f);
|
||||
MOZ_ASSERT(p);
|
||||
|
||||
uint32_t offset = p->value();
|
||||
MOZ_ASSERT(offset < functionWrapperCode_->instructionsSize());
|
||||
|
||||
return functionWrapperCode_->raw() + offset;
|
||||
return trampolineCode(p->value());
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
|
@ -863,7 +841,6 @@ JitCode::finalize(FreeOp* fop)
|
|||
|
||||
IonScript::IonScript()
|
||||
: method_(nullptr),
|
||||
deoptTable_(nullptr),
|
||||
osrPc_(nullptr),
|
||||
osrEntryOffset_(0),
|
||||
skipArgCheckEntryOffset_(0),
|
||||
|
@ -1022,9 +999,6 @@ IonScript::trace(JSTracer* trc)
|
|||
if (method_)
|
||||
TraceEdge(trc, &method_, "method");
|
||||
|
||||
if (deoptTable_)
|
||||
TraceEdge(trc, &deoptTable_, "deoptimizationTable");
|
||||
|
||||
for (size_t i = 0; i < numConstants(); i++)
|
||||
TraceEdge(trc, &getConstant(i), "constant");
|
||||
|
||||
|
@ -2821,10 +2795,11 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
|||
if (!frame.isIonScripted())
|
||||
continue;
|
||||
|
||||
JitRuntime* jrt = fop->runtime()->jitRuntime();
|
||||
|
||||
bool calledFromLinkStub = false;
|
||||
JitCode* lazyLinkStub = fop->runtime()->jitRuntime()->lazyLinkStub();
|
||||
if (frame.returnAddressToFp() >= lazyLinkStub->raw() &&
|
||||
frame.returnAddressToFp() < lazyLinkStub->rawEnd())
|
||||
if (frame.returnAddressToFp() >= jrt->lazyLinkStub().value &&
|
||||
frame.returnAddressToFp() < jrt->lazyLinkStubEnd().value)
|
||||
{
|
||||
calledFromLinkStub = true;
|
||||
}
|
||||
|
|
|
@ -3205,7 +3205,7 @@ jit::ExtractLinearSum(MDefinition* ins, MathSpace space)
|
|||
if (ins->isAdd()) {
|
||||
int32_t constant;
|
||||
if (space == MathSpace::Modulo)
|
||||
constant = lsum.constant + rsum.constant;
|
||||
constant = uint32_t(lsum.constant) + uint32_t(rsum.constant);
|
||||
else if (!SafeAdd(lsum.constant, rsum.constant, &constant))
|
||||
return SimpleLinearSum(ins, 0);
|
||||
return SimpleLinearSum(lsum.term ? lsum.term : rsum.term, constant);
|
||||
|
@ -3216,7 +3216,7 @@ jit::ExtractLinearSum(MDefinition* ins, MathSpace space)
|
|||
if (lsum.term) {
|
||||
int32_t constant;
|
||||
if (space == MathSpace::Modulo)
|
||||
constant = lsum.constant - rsum.constant;
|
||||
constant = uint32_t(lsum.constant) - uint32_t(rsum.constant);
|
||||
else if (!SafeSub(lsum.constant, rsum.constant, &constant))
|
||||
return SimpleLinearSum(ins, 0);
|
||||
return SimpleLinearSum(lsum.term, constant);
|
||||
|
|
|
@ -358,13 +358,13 @@ IonCacheIRCompiler::callVM(MacroAssembler& masm, const VMFunction& fun)
|
|||
{
|
||||
MOZ_ASSERT(calledPrepareVMCall_);
|
||||
|
||||
uint8_t* code = cx_->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
TrampolinePtr code = cx_->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
|
||||
uint32_t frameSize = fun.explicitStackSlots() * sizeof(void*);
|
||||
uint32_t descriptor = MakeFrameDescriptor(frameSize, JitFrame_IonICCall,
|
||||
ExitFrameLayout::Size());
|
||||
masm.Push(Imm32(descriptor));
|
||||
masm.callJit(ImmPtr(code));
|
||||
masm.callJit(code);
|
||||
|
||||
// Remove rest of the frame left on the stack. We remove the return address
|
||||
// which is implicitly poped when returning.
|
||||
|
|
|
@ -168,9 +168,6 @@ struct IonScript
|
|||
// Code pointer containing the actual method.
|
||||
PreBarrieredJitCode method_;
|
||||
|
||||
// Deoptimization table used by this method.
|
||||
PreBarrieredJitCode deoptTable_;
|
||||
|
||||
// Entrypoint for OSR, or nullptr.
|
||||
jsbytecode* osrPc_;
|
||||
|
||||
|
@ -363,9 +360,6 @@ struct IonScript
|
|||
MOZ_ASSERT(!invalidated());
|
||||
method_ = code;
|
||||
}
|
||||
void setDeoptTable(JitCode* code) {
|
||||
deoptTable_ = code;
|
||||
}
|
||||
void setOsrPc(jsbytecode* osrPc) {
|
||||
osrPc_ = osrPc;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ EnterJit(JSContext* cx, RunState& state, uint8_t* code)
|
|||
|
||||
unsigned numFormals = script->functionNonDelazifying()->nargs();
|
||||
if (numFormals > numActualArgs)
|
||||
code = cx->runtime()->jitRuntime()->getArgumentsRectifier()->raw();
|
||||
code = cx->runtime()->jitRuntime()->getArgumentsRectifier().value;
|
||||
} else {
|
||||
numActualArgs = 0;
|
||||
constructing = false;
|
||||
|
|
|
@ -88,45 +88,53 @@ class JitRuntime
|
|||
ActiveThreadData<ExecutableAllocator> backedgeExecAlloc_;
|
||||
|
||||
// Shared exception-handler tail.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> exceptionTail_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> exceptionTailOffset_;
|
||||
|
||||
// Shared post-bailout-handler tail.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> bailoutTail_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> bailoutTailOffset_;
|
||||
|
||||
// Shared profiler exit frame tail.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> profilerExitFrameTail_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> profilerExitFrameTailOffset_;
|
||||
|
||||
// Trampoline for entering JIT code.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> enterJIT_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> enterJITOffset_;
|
||||
|
||||
// Vector mapping frame class sizes to bailout tables.
|
||||
typedef Vector<JitCode*, 4, SystemAllocPolicy> BailoutTableVector;
|
||||
struct BailoutTable {
|
||||
uint32_t startOffset;
|
||||
uint32_t size;
|
||||
BailoutTable(uint32_t startOffset, uint32_t size)
|
||||
: startOffset(startOffset), size(size)
|
||||
{}
|
||||
};
|
||||
typedef Vector<BailoutTable, 4, SystemAllocPolicy> BailoutTableVector;
|
||||
ExclusiveAccessLockWriteOnceData<BailoutTableVector> bailoutTables_;
|
||||
|
||||
// Generic bailout table; used if the bailout table overflows.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> bailoutHandler_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> bailoutHandlerOffset_;
|
||||
|
||||
// Argument-rectifying thunk, in the case of insufficient arguments passed
|
||||
// to a function call site.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> argumentsRectifier_;
|
||||
ExclusiveAccessLockWriteOnceData<void*> argumentsRectifierReturnAddr_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> argumentsRectifierOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> argumentsRectifierReturnOffset_;
|
||||
|
||||
// Thunk that invalides an (Ion compiled) caller on the Ion stack.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> invalidator_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> invalidatorOffset_;
|
||||
|
||||
// Thunk that calls the GC pre barrier.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> valuePreBarrier_;
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> stringPreBarrier_;
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> objectPreBarrier_;
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> shapePreBarrier_;
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> objectGroupPreBarrier_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> valuePreBarrierOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> stringPreBarrierOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> objectPreBarrierOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> shapePreBarrierOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> objectGroupPreBarrierOffset_;
|
||||
|
||||
// Thunk to call malloc/free.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> mallocStub_;
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> freeStub_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> mallocStubOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> freeStubOffset_;
|
||||
|
||||
// Thunk called to finish compilation of an IonScript.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> lazyLinkStub_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> lazyLinkStubOffset_;
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> lazyLinkStubEndOffset_;
|
||||
|
||||
// Thunk used by the debugger for breakpoint and step mode.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> debugTrapHandler_;
|
||||
|
@ -135,11 +143,11 @@ class JitRuntime
|
|||
ExclusiveAccessLockWriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
|
||||
ExclusiveAccessLockWriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
|
||||
|
||||
// Code for all VMFunction wrappers.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> functionWrapperCode_;
|
||||
// Code for trampolines and VMFunction wrappers.
|
||||
ExclusiveAccessLockWriteOnceData<JitCode*> trampolineCode_;
|
||||
|
||||
// Map VMFunction addresses to the offset of the wrapper in
|
||||
// functionWrapperCode_.
|
||||
// trampolineCode_.
|
||||
using VMWrapperMap = HashMap<const VMFunction*, uint32_t, VMFunction>;
|
||||
ExclusiveAccessLockWriteOnceData<VMWrapperMap*> functionWrappers_;
|
||||
|
||||
|
@ -151,18 +159,18 @@ class JitRuntime
|
|||
UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_;
|
||||
|
||||
private:
|
||||
JitCode* generateLazyLinkStub(JSContext* cx);
|
||||
JitCode* generateProfilerExitFrameTailStub(JSContext* cx);
|
||||
JitCode* generateExceptionTailStub(JSContext* cx, void* handler);
|
||||
JitCode* generateBailoutTailStub(JSContext* cx);
|
||||
JitCode* generateEnterJIT(JSContext* cx);
|
||||
JitCode* generateArgumentsRectifier(JSContext* cx, void** returnAddrOut);
|
||||
JitCode* generateBailoutTable(JSContext* cx, uint32_t frameClass);
|
||||
JitCode* generateBailoutHandler(JSContext* cx);
|
||||
JitCode* generateInvalidator(JSContext* cx);
|
||||
JitCode* generatePreBarrier(JSContext* cx, MIRType type);
|
||||
JitCode* generateMallocStub(JSContext* cx);
|
||||
JitCode* generateFreeStub(JSContext* cx);
|
||||
void generateLazyLinkStub(MacroAssembler& masm);
|
||||
void generateProfilerExitFrameTailStub(MacroAssembler& masm, Label* profilerExitTail);
|
||||
void generateExceptionTailStub(MacroAssembler& masm, void* handler, Label* profilerExitTail);
|
||||
void generateBailoutTailStub(MacroAssembler& masm, Label* bailoutTail);
|
||||
void generateEnterJIT(JSContext* cx, MacroAssembler& masm);
|
||||
void generateArgumentsRectifier(MacroAssembler& masm);
|
||||
BailoutTable generateBailoutTable(MacroAssembler& masm, Label* bailoutTail, uint32_t frameClass);
|
||||
void generateBailoutHandler(MacroAssembler& masm, Label* bailoutTail);
|
||||
void generateInvalidator(MacroAssembler& masm, Label* bailoutTail);
|
||||
uint32_t generatePreBarrier(JSContext* cx, MacroAssembler& masm, MIRType type);
|
||||
void generateMallocStub(MacroAssembler& masm);
|
||||
void generateFreeStub(MacroAssembler& masm);
|
||||
JitCode* generateDebugTrapHandler(JSContext* cx);
|
||||
JitCode* generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
|
||||
bool generateVMWrapper(JSContext* cx, MacroAssembler& masm, const VMFunction& f);
|
||||
|
@ -176,6 +184,14 @@ class JitRuntime
|
|||
return generateTLEventVM(cx, masm, f, /* enter = */ false);
|
||||
}
|
||||
|
||||
uint32_t startTrampolineCode(MacroAssembler& masm);
|
||||
|
||||
TrampolinePtr trampolineCode(uint32_t offset) const {
|
||||
MOZ_ASSERT(offset > 0);
|
||||
MOZ_ASSERT(offset < trampolineCode_->instructionsSize());
|
||||
return TrampolinePtr(trampolineCode_->raw() + offset);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit JitRuntime(JSRuntime* rt);
|
||||
~JitRuntime();
|
||||
|
@ -228,66 +244,75 @@ class JitRuntime
|
|||
return preventBackedgePatching_;
|
||||
}
|
||||
|
||||
uint8_t* getVMWrapper(const VMFunction& f) const;
|
||||
TrampolinePtr getVMWrapper(const VMFunction& f) const;
|
||||
JitCode* debugTrapHandler(JSContext* cx);
|
||||
JitCode* getBaselineDebugModeOSRHandler(JSContext* cx);
|
||||
void* getBaselineDebugModeOSRHandlerAddress(JSContext* cx, bool popFrameReg);
|
||||
|
||||
JitCode* getGenericBailoutHandler() const {
|
||||
return bailoutHandler_;
|
||||
TrampolinePtr getGenericBailoutHandler() const {
|
||||
return trampolineCode(bailoutHandlerOffset_);
|
||||
}
|
||||
|
||||
JitCode* getExceptionTail() const {
|
||||
return exceptionTail_;
|
||||
TrampolinePtr getExceptionTail() const {
|
||||
return trampolineCode(exceptionTailOffset_);
|
||||
}
|
||||
|
||||
JitCode* getBailoutTail() const {
|
||||
return bailoutTail_;
|
||||
TrampolinePtr getBailoutTail() const {
|
||||
return trampolineCode(bailoutTailOffset_);
|
||||
}
|
||||
|
||||
JitCode* getProfilerExitFrameTail() const {
|
||||
return profilerExitFrameTail_;
|
||||
TrampolinePtr getProfilerExitFrameTail() const {
|
||||
return trampolineCode(profilerExitFrameTailOffset_);
|
||||
}
|
||||
|
||||
JitCode* getBailoutTable(const FrameSizeClass& frameClass) const;
|
||||
TrampolinePtr getBailoutTable(const FrameSizeClass& frameClass) const;
|
||||
uint32_t getBailoutTableSize(const FrameSizeClass& frameClass) const;
|
||||
|
||||
JitCode* getArgumentsRectifier() const {
|
||||
return argumentsRectifier_;
|
||||
TrampolinePtr getArgumentsRectifier() const {
|
||||
return trampolineCode(argumentsRectifierOffset_);
|
||||
}
|
||||
|
||||
void* getArgumentsRectifierReturnAddr() const {
|
||||
return argumentsRectifierReturnAddr_;
|
||||
TrampolinePtr getArgumentsRectifierReturnAddr() const {
|
||||
return trampolineCode(argumentsRectifierReturnOffset_);
|
||||
}
|
||||
|
||||
JitCode* getInvalidationThunk() const {
|
||||
return invalidator_;
|
||||
TrampolinePtr getInvalidationThunk() const {
|
||||
return trampolineCode(invalidatorOffset_);
|
||||
}
|
||||
|
||||
EnterJitCode enterJit() const {
|
||||
return enterJIT_->as<EnterJitCode>();
|
||||
return JS_DATA_TO_FUNC_PTR(EnterJitCode, trampolineCode(enterJITOffset_).value);
|
||||
}
|
||||
|
||||
JitCode* preBarrier(MIRType type) const {
|
||||
TrampolinePtr preBarrier(MIRType type) const {
|
||||
switch (type) {
|
||||
case MIRType::Value: return valuePreBarrier_;
|
||||
case MIRType::String: return stringPreBarrier_;
|
||||
case MIRType::Object: return objectPreBarrier_;
|
||||
case MIRType::Shape: return shapePreBarrier_;
|
||||
case MIRType::ObjectGroup: return objectGroupPreBarrier_;
|
||||
case MIRType::Value:
|
||||
return trampolineCode(valuePreBarrierOffset_);
|
||||
case MIRType::String:
|
||||
return trampolineCode(stringPreBarrierOffset_);
|
||||
case MIRType::Object:
|
||||
return trampolineCode(objectPreBarrierOffset_);
|
||||
case MIRType::Shape:
|
||||
return trampolineCode(shapePreBarrierOffset_);
|
||||
case MIRType::ObjectGroup:
|
||||
return trampolineCode(objectGroupPreBarrierOffset_);
|
||||
default: MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
JitCode* mallocStub() const {
|
||||
return mallocStub_;
|
||||
TrampolinePtr mallocStub() const {
|
||||
return trampolineCode(mallocStubOffset_);
|
||||
}
|
||||
|
||||
JitCode* freeStub() const {
|
||||
return freeStub_;
|
||||
TrampolinePtr freeStub() const {
|
||||
return trampolineCode(freeStubOffset_);
|
||||
}
|
||||
|
||||
JitCode* lazyLinkStub() const {
|
||||
return lazyLinkStub_;
|
||||
TrampolinePtr lazyLinkStub() const {
|
||||
return trampolineCode(lazyLinkStubOffset_);
|
||||
}
|
||||
TrampolinePtr lazyLinkStubEnd() const {
|
||||
return trampolineCode(lazyLinkStubEndOffset_);
|
||||
}
|
||||
|
||||
bool hasJitcodeGlobalTable() const {
|
||||
|
|
|
@ -1152,7 +1152,6 @@ TraceJitExitFrame(JSTracer* trc, const JSJitFrameIter& frame)
|
|||
LazyLinkExitFrameLayout* ll = frame.exitFrame()->as<LazyLinkExitFrameLayout>();
|
||||
JitFrameLayout* layout = ll->jsFrame();
|
||||
|
||||
TraceRoot(trc, ll->stubCode(), "lazy-link-code");
|
||||
layout->replaceCalleeToken(TraceCalleeToken(trc, layout->calleeToken()));
|
||||
TraceThisAndArguments(trc, frame);
|
||||
return;
|
||||
|
|
|
@ -830,7 +830,6 @@ struct IonDOMMethodExitFrameLayoutTraits {
|
|||
class LazyLinkExitFrameLayout
|
||||
{
|
||||
protected: // silence clang warning about unused private fields
|
||||
JitCode* stubCode_;
|
||||
ExitFooterFrame footer_;
|
||||
JitFrameLayout exit_;
|
||||
|
||||
|
@ -841,9 +840,6 @@ class LazyLinkExitFrameLayout
|
|||
return sizeof(LazyLinkExitFrameLayout);
|
||||
}
|
||||
|
||||
inline JitCode** stubCode() {
|
||||
return &stubCode_;
|
||||
}
|
||||
inline JitFrameLayout* jsFrame() {
|
||||
return &exit_;
|
||||
}
|
||||
|
|
|
@ -1109,7 +1109,7 @@ JitcodeRegionEntry::WriteDelta(CompactBufferWriter& writer,
|
|||
nativeDelta <= ENC3_NATIVE_DELTA_MAX)
|
||||
{
|
||||
uint32_t encVal = ENC3_MASK_VAL |
|
||||
((pcDelta << ENC3_PC_DELTA_SHIFT) & ENC3_PC_DELTA_MASK) |
|
||||
((uint32_t(pcDelta) << ENC3_PC_DELTA_SHIFT) & ENC3_PC_DELTA_MASK) |
|
||||
(nativeDelta << ENC3_NATIVE_DELTA_SHIFT);
|
||||
writer.writeByte(encVal & 0xff);
|
||||
writer.writeByte((encVal >> 8) & 0xff);
|
||||
|
@ -1122,7 +1122,7 @@ JitcodeRegionEntry::WriteDelta(CompactBufferWriter& writer,
|
|||
nativeDelta <= ENC4_NATIVE_DELTA_MAX)
|
||||
{
|
||||
uint32_t encVal = ENC4_MASK_VAL |
|
||||
((pcDelta << ENC4_PC_DELTA_SHIFT) & ENC4_PC_DELTA_MASK) |
|
||||
((uint32_t(pcDelta) << ENC4_PC_DELTA_SHIFT) & ENC4_PC_DELTA_MASK) |
|
||||
(nativeDelta << ENC4_NATIVE_DELTA_SHIFT);
|
||||
writer.writeByte(encVal & 0xff);
|
||||
writer.writeByte((encVal >> 8) & 0xff);
|
||||
|
|
|
@ -3508,7 +3508,7 @@ IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayTyp
|
|||
if (!arg0Types)
|
||||
return false;
|
||||
|
||||
TemporaryTypeSet::TypedArraySharedness sharedness;
|
||||
TemporaryTypeSet::TypedArraySharedness sharedness = TemporaryTypeSet::UnknownSharedness;
|
||||
*arrayType = arg0Types->getTypedArrayType(constraints(), &sharedness);
|
||||
*requiresTagCheck = sharedness != TemporaryTypeSet::KnownShared;
|
||||
switch (*arrayType) {
|
||||
|
|
|
@ -82,6 +82,12 @@ MacroAssembler::PushWithPatch(ImmPtr imm)
|
|||
// ===============================================================
|
||||
// Simple call functions.
|
||||
|
||||
void
|
||||
MacroAssembler::call(TrampolinePtr code)
|
||||
{
|
||||
call(ImmPtr(code.value));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg)
|
||||
{
|
||||
|
@ -234,7 +240,7 @@ MacroAssembler::callJit(JitCode* callee)
|
|||
}
|
||||
|
||||
uint32_t
|
||||
MacroAssembler::callJit(ImmPtr code)
|
||||
MacroAssembler::callJit(TrampolinePtr code)
|
||||
{
|
||||
AutoProfilerCallInstrumentation profiler(*this);
|
||||
call(code);
|
||||
|
@ -304,14 +310,6 @@ MacroAssembler::buildFakeExitFrame(Register scratch)
|
|||
// ===============================================================
|
||||
// Exit frame footer.
|
||||
|
||||
void
|
||||
MacroAssembler::PushStubCode()
|
||||
{
|
||||
// Make sure that we do not erase an existing self-reference.
|
||||
MOZ_ASSERT(!hasSelfReference());
|
||||
selfReferencePatch_ = PushWithPatch(ImmWord(-1));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::enterExitFrame(Register cxreg, Register scratch, const VMFunction* f)
|
||||
{
|
||||
|
@ -341,12 +339,6 @@ MacroAssembler::leaveExitFrame(size_t extraFrame)
|
|||
freeStack(ExitFooterFrame::Size() + extraFrame);
|
||||
}
|
||||
|
||||
bool
|
||||
MacroAssembler::hasSelfReference() const
|
||||
{
|
||||
return selfReferencePatch_.bound();
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Move instructions
|
||||
|
||||
|
|
|
@ -1700,7 +1700,7 @@ MacroAssembler::handleFailure()
|
|||
{
|
||||
// Re-entry code is irrelevant because the exception will leave the
|
||||
// running function and never come back
|
||||
JitCode* excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail();
|
||||
TrampolinePtr excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail();
|
||||
jump(excTail);
|
||||
}
|
||||
|
||||
|
@ -2361,7 +2361,6 @@ void
|
|||
MacroAssembler::link(JitCode* code)
|
||||
{
|
||||
MOZ_ASSERT(!oom());
|
||||
linkSelfReference(code);
|
||||
linkProfilerCallSites(code);
|
||||
}
|
||||
|
||||
|
@ -2881,19 +2880,6 @@ MacroAssembler::linkExitFrame(Register cxreg, Register scratch)
|
|||
storeStackPtr(Address(scratch, JitActivation::offsetOfPackedExitFP()));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::linkSelfReference(JitCode* code)
|
||||
{
|
||||
// If this code can transition to C++ code and witness a GC, then we need to store
|
||||
// the JitCode onto the stack in order to GC it correctly. exitCodePatch should
|
||||
// be unset if the code never needed to push its JitCode*.
|
||||
if (hasSelfReference()) {
|
||||
PatchDataWithValueCheck(CodeLocationLabel(code, selfReferencePatch_),
|
||||
ImmPtr(code),
|
||||
ImmPtr((void*)-1));
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Branch functions
|
||||
|
||||
|
|
|
@ -512,6 +512,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// Call a target JitCode, which must be traceable, and may be movable.
|
||||
void call(JitCode* c) PER_SHARED_ARCH;
|
||||
|
||||
inline void call(TrampolinePtr code);
|
||||
|
||||
inline void call(const wasm::CallSiteDesc& desc, const Register reg);
|
||||
inline void call(const wasm::CallSiteDesc& desc, uint32_t funcDefIndex);
|
||||
inline void call(const wasm::CallSiteDesc& desc, wasm::Trap trap);
|
||||
|
@ -651,7 +653,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline uint32_t callJitNoProfiler(Register callee);
|
||||
inline uint32_t callJit(Register callee);
|
||||
inline uint32_t callJit(JitCode* code);
|
||||
inline uint32_t callJit(ImmPtr code);
|
||||
inline uint32_t callJit(TrampolinePtr code);
|
||||
|
||||
// The frame descriptor is the second field of all Jit frames, pushed before
|
||||
// calling the Jit function. It is a composite value defined in JitFrames.h
|
||||
|
@ -700,17 +702,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
//
|
||||
// See JitFrames.h, and MarkJitExitFrame in JitFrames.cpp.
|
||||
|
||||
// If the current piece of code might be garbage collected, then the exit
|
||||
// frame footer must contain a pointer to the current JitCode, such that the
|
||||
// garbage collector can keep the code alive as long this code is on the
|
||||
// stack. This function pushes a placeholder which is replaced when the code
|
||||
// is linked.
|
||||
inline void PushStubCode();
|
||||
|
||||
// Return true if the code contains a self-reference which needs to be
|
||||
// patched when the code is linked.
|
||||
inline bool hasSelfReference() const;
|
||||
|
||||
// Push stub code and the VMFunction pointer.
|
||||
inline void enterExitFrame(Register cxreg, Register scratch, const VMFunction* f);
|
||||
|
||||
|
@ -729,14 +720,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// current thread, which should be the location of the latest exit frame.
|
||||
void linkExitFrame(Register cxreg, Register scratch);
|
||||
|
||||
// Patch the value of PushStubCode with the pointer to the finalized code.
|
||||
void linkSelfReference(JitCode* code);
|
||||
|
||||
// If the JitCode that created this assembler needs to transition into the VM,
|
||||
// we want to store the JitCode on the stack in order to mark it during a GC.
|
||||
// This is a reference to a patch location where the JitCode* will be written.
|
||||
CodeOffset selfReferencePatch_;
|
||||
|
||||
public:
|
||||
// ===============================================================
|
||||
// Move instructions
|
||||
|
@ -1699,7 +1682,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
computeEffectiveAddress(address, PreBarrierReg);
|
||||
|
||||
const JitRuntime* rt = GetJitContext()->runtime->jitRuntime();
|
||||
JitCode* preBarrier = rt->preBarrier(type);
|
||||
TrampolinePtr preBarrier = rt->preBarrier(type);
|
||||
|
||||
call(preBarrier);
|
||||
Pop(PreBarrierReg);
|
||||
|
@ -1949,6 +1932,12 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
Push(scratch);
|
||||
}
|
||||
|
||||
using MacroAssemblerSpecific::movePtr;
|
||||
|
||||
void movePtr(TrampolinePtr ptr, Register dest) {
|
||||
movePtr(ImmPtr(ptr.value), dest);
|
||||
}
|
||||
|
||||
private:
|
||||
void handleFailure();
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ MoveOperand::MoveOperand(MacroAssembler& masm, const ABIArg& arg)
|
|||
code_ = masm.getStackPointer().code();
|
||||
disp_ = arg.offsetFromArgBase();
|
||||
break;
|
||||
case ABIArg::Uninitialized:
|
||||
MOZ_CRASH("Uninitialized ABIArg kind");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1305,7 +1305,8 @@ class ABIArg
|
|||
GPR_PAIR,
|
||||
#endif
|
||||
FPU,
|
||||
Stack
|
||||
Stack,
|
||||
Uninitialized = -1
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -1317,7 +1318,7 @@ class ABIArg
|
|||
} u;
|
||||
|
||||
public:
|
||||
ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; }
|
||||
ABIArg() : kind_(Uninitialized) { u.offset_ = -1; }
|
||||
explicit ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
|
||||
explicit ABIArg(Register gprLow, Register gprHigh)
|
||||
{
|
||||
|
@ -1333,9 +1334,12 @@ class ABIArg
|
|||
explicit ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
|
||||
explicit ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
|
||||
|
||||
Kind kind() const { return kind_; }
|
||||
Kind kind() const {
|
||||
MOZ_ASSERT(kind_ != Uninitialized);
|
||||
return kind_;
|
||||
}
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
bool isGeneralRegPair() const { return kind_ == GPR_PAIR; }
|
||||
bool isGeneralRegPair() const { return kind() == GPR_PAIR; }
|
||||
#else
|
||||
bool isGeneralRegPair() const { return false; }
|
||||
#endif
|
||||
|
@ -1369,22 +1373,22 @@ class ABIArg
|
|||
}
|
||||
|
||||
bool argInRegister() const { return kind() != Stack; }
|
||||
AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
|
||||
AnyRegister reg() const { return kind() == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
|
||||
|
||||
bool operator==(const ABIArg& rhs) const {
|
||||
if (kind_ != rhs.kind_)
|
||||
return false;
|
||||
|
||||
switch((int8_t)kind_) {
|
||||
switch(kind_) {
|
||||
case GPR: return u.gpr_ == rhs.u.gpr_;
|
||||
#if defined(JS_CODEGEN_REGISTER_PAIR)
|
||||
case GPR_PAIR: return u.gpr_ == rhs.u.gpr_;
|
||||
#endif
|
||||
case FPU: return u.fpu_ == rhs.u.fpu_;
|
||||
case Stack: return u.offset_ == rhs.u.offset_;
|
||||
case -1: return true;
|
||||
default: MOZ_CRASH("Invalid value for ABIArg kind");
|
||||
case Uninitialized: return true;
|
||||
}
|
||||
MOZ_CRASH("Invalid value for ABIArg kind");
|
||||
}
|
||||
|
||||
bool operator!=(const ABIArg& rhs) const {
|
||||
|
|
|
@ -554,7 +554,7 @@ ICStubCompiler::getStubCode()
|
|||
bool
|
||||
ICStubCompiler::tailCallVM(const VMFunction& fun, MacroAssembler& masm)
|
||||
{
|
||||
uint8_t* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
MOZ_ASSERT(fun.expectTailCall == TailCall);
|
||||
uint32_t argSize = fun.explicitStackSlots() * sizeof(void*);
|
||||
if (engine_ == Engine::Baseline) {
|
||||
|
@ -571,7 +571,7 @@ ICStubCompiler::callVM(const VMFunction& fun, MacroAssembler& masm)
|
|||
{
|
||||
MOZ_ASSERT(inStubFrame_);
|
||||
|
||||
uint8_t* code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
|
||||
MOZ_ASSERT(fun.expectTailCall == NonTailCall);
|
||||
MOZ_ASSERT(engine_ == Engine::Baseline);
|
||||
|
||||
|
|
|
@ -90,12 +90,15 @@ BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
|
|||
|
||||
// Compute the snapshot offset from the bailout ID.
|
||||
JSRuntime* rt = activation->compartment()->runtimeFromActiveCooperatingThread();
|
||||
JitCode* code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
|
||||
TrampolinePtr code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
|
||||
#ifdef DEBUG
|
||||
uint32_t tableSize = rt->jitRuntime()->getBailoutTableSize(bailout->frameClass());
|
||||
#endif
|
||||
uintptr_t tableOffset = bailout->tableOffset();
|
||||
uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw()));
|
||||
uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code.value));
|
||||
|
||||
MOZ_ASSERT(tableOffset >= tableStart &&
|
||||
tableOffset < tableStart + code->instructionsSize());
|
||||
tableOffset < tableStart + tableSize);
|
||||
MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
|
||||
|
||||
uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
|
||||
|
|
|
@ -138,8 +138,8 @@ CodeGeneratorARM::generateOutOfLineCode()
|
|||
// Push the frame size, so the handler can recover the IonScript.
|
||||
masm.ma_mov(Imm32(frameSize()), lr);
|
||||
|
||||
JitCode* handler = gen->jitRuntime()->getGenericBailoutHandler();
|
||||
masm.branch(handler);
|
||||
TrampolinePtr handler = gen->jitRuntime()->getGenericBailoutHandler();
|
||||
masm.jump(handler);
|
||||
}
|
||||
|
||||
return !masm.oom();
|
||||
|
@ -157,7 +157,7 @@ CodeGeneratorARM::bailoutIf(Assembler::Condition condition, LSnapshot* snapshot)
|
|||
frameClass_.frameSize() == masm.framePushed());
|
||||
|
||||
if (assignBailoutId(snapshot)) {
|
||||
uint8_t* bailoutTable = Assembler::BailoutTableStart(deoptTable_->raw());
|
||||
uint8_t* bailoutTable = Assembler::BailoutTableStart(deoptTable_->value);
|
||||
uint8_t* code = bailoutTable + snapshot->bailoutId() * BAILOUT_TABLE_ENTRY_SIZE;
|
||||
masm.ma_b(code, condition);
|
||||
return;
|
||||
|
@ -1786,9 +1786,9 @@ CodeGeneratorARM::generateInvalidateEpilogue()
|
|||
|
||||
// Push the Ion script onto the stack (when we determine what that pointer is).
|
||||
invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
|
||||
JitCode* thunk = gen->jitRuntime()->getInvalidationThunk();
|
||||
|
||||
masm.branch(thunk);
|
||||
TrampolinePtr thunk = gen->jitRuntime()->getInvalidationThunk();
|
||||
masm.jump(thunk);
|
||||
|
||||
// We should never reach this point in JIT code -- the invalidation thunk
|
||||
// should pop the invalidated JS frame and return directly to its caller.
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче