Merge inbound to mozilla-central r=merge a=merge

This commit is contained in:
Ciure Andrei 2017-11-17 11:59:03 +02:00
Родитель 214be74c6c 8fbfdec507
Коммит 92d28bd8f2
220 изменённых файлов: 8478 добавлений и 6155 удалений

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

@ -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,

1
dom/cache/DBSchema.cpp поставляемый
Просмотреть файл

@ -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.

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