import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1218706 - Make 'unicode-bidi: isolate' the default for elements with a dir attribute. r=dbaron,jfkthame (037a5aaf57)
- Bug 743198 part 7 - Add :fullscreen pseudo class. r=heycam (05eb82ccc9)
- missing bits of  Bug 1242904 - Update Brotli t (f4f569d859)
- Bug 1235298 - Annotate intentional switch fallthroughs to suppress -Wimplicit-fallthrough warnings in netwerk/. r=mcmanus (c4ae414769)
- Bug 1244841 - Don't measure SharedArrayBuffer objects multiple times. r=lth. (e9b665dc82)
- Bug 234031 - broken parsing of xlen in gzip rfc 1952 r=mcmanus (c905b50417)
- Bug 1239605 - filter insertions into the global object. r=jandem (35520bc5c8)
- Bug 1248681 - Warn if the result of putWrapper goes unused; r=sfink (8051888ef8)
- Bug 1246293 - Fix a typo in DefineSelfHostedProperty; r=till (5e05a76b2a)
- Bug 1243808 - Allow modules to be compiled off main thread r=shu (51e5adca0a)
- Bug 1241767 - avoid default-only switch to placate MSVC. r=bbouvier (392aa8eda0)
- Bug 1239710 - Use CountingSort for Uint8Array and Int8Array; r=mrrrgn (6f394ab442)
- Bug 1246860 - Preserve holes when sorting arrays with a custom comparator. r=till (725b091e55)
- Bug 1247283 - Improve self-hosted Array.sort performance; r=till (ab1f3ddb74)
- Bug 1248717 - Don't initialize variables in a for head with var, then use them later. r=jorendorff (87a77f9623)
- Bug 1242196 - Use RadixSort for typed arrays. r=mrrrgn (a280ea097d)
- Bug 1246927 - Fix OOM handling in usages of GlobalObject::maybeGetIntrinsicValue. r=arai (f7f3761c45)
- Bug 1248405 - Recover from JSObject::getGroup OOM in CanOptimizeForDenseStorage. r=jandem (68ea32c044)
- Bug 1225905 - create a mozharness script that manages each beet mover task logic, NPOTB DONTBUILD r=rail (076f25536f)
- Bug 1246074 - add partials template config for mozharness beetmover, DONTBUILD r=rail (2e42c78d92)
- Bug 1246074 - add partials mozharness beetmover, custom tc artifact location, DONTBUILD NPOTB r=rail (c74fe0755a)
- Bug 1210538 - Add antivirus checks to release promotion graph a=rail (56de774389)
- Bug 1238610 - Restore compartment debug mode flags if adding a debuggee global fails r=jimb (f8a9a1fa85)
- Bug 1243851 - Treat enter as shift+enter if input is valid but incomplete; r=fitzgen, bgrins (f27c959bc0)
- Bug 1238610 - Fix implicit constructor errors r=me (6f26f92763)
- Bug 1242111 - Handle OOM in UpdateExecutionObservabilityOfScriptsInZone. (r=jimb) (91b125725f)
- Bug 1240503 - Skip the initial block scope when unwinding scopes due to an exception that's thrown in the prologue before the scope chain is properly initialized for a script that starts with a block scope. (r=jorendorff) (0247fc8848)
- Bug 1242111 - Fix references to oomTest. (r=me) (a9dc13a648)
- Bug 1240546 - Handle OOM in updateObservesAllExecutionOnDebuggees. (r=jimb) (5d7e3a49f4)
- Bug 1245961 - Throw a TypeError if less than one argument is supplied to isCompilableUnit;r=fitzgen (f896abb042)
- Bug 1240803 - Handle OOM in replaceFrameGuts. (r=jimb) (2d43384c72)
- Bug 1248094 - Simplify PCLocationMap with GCHashMap; r=fitzgen (b28d983bbd)
- we don't care much abut 68k sadly (51c50300c5)
- Bug 1233786 - JSScript::initScriptCounts should report OOMs. r=bhackett (eb42f7b8c1)
- Bug 1233178 - Move ScriptCounts allocation outside the HashMap. r=bhackett (c3fa6d487c)
- Bug 1141579 - Synchronize access to warmUpCount; r=jandem (a5b72cdf94)
- Bug 1203696: Improve comments about lazily-initialized member of js::LazyScript. r=shu (caa895612d)
- Bug 1221992 - Fix test using GetMostRecentWindow from the child process. r=smaug (07affe8195)
- Bug 1235636 - rewrite PCToLineNumber; r=fitzgen (9dc9ff013e)
- Bug 1232100 - "Check charsWritten in non-debug builds.". r=jcoppeard (fc5a64e621)
- last bit of  Bug 1197932 (86277af34e)
- Bug 1067049 - Implement arguments[@@iterator]. r=evilpie (543e513269)
- Bug 1248930 - Use Int32Value in ArrayBufferObject::BYTE_LENGTH_SLOT. r=lth (71e3a9ee51)
- Bug 1113685 - Report the right name when calling selfhosted functions on incompatible objects. r=till (51f68d4f8d)
- some symbol cleanup (83fca10034)
- Bug 1165011 - Remove Symbol_isRegExp. r=jorendorff (46a2d293cc)
- Bug 1122900: Make libyuv compile with MSVC 2015, r=rjesup. (9e147c7ba7)
- bug 1241453 - clean up GetAccessibleWrap() r=davidb (01e37c5012)
- Bug 1243331 - Prevent G_DEFINE_TYPE_EXTENDED macro from producing a fatal warning, r=tbsaunde (8bf031c4b9)
- Bug 1232527 - Call into WMF PDM to determine if WMF can decode instead of using GMPVideoDecoderTrialCreator. r=jwwang (7d2b1f16f1)
- Bug 1229475 - Fix gen-sources for libopus 1.1.1. r=cpearce (1e5a768d94)
- Bug 1229475 - Update libopus to 1.1.1 release. r=jmspeex (0b73488ab3)
- Bug 1139087 - Add moz.build bugzilla metadata for codecs. r=kinetik,gps (3d906f8f5a)
- Bug 1229475 - libopus: Patch out asm flags for run_analysis. r=jmspeex (bfa15edac1)
- Bug 1229475 - Fix unified build. r=cpearce (bbeda94cfc)
- Bug 1239078 - Update libopus to 1.1.2 release. r=kinetik (9990b00867)
- Bug 1239078 - Bump libopus update script for 1.1.2. r=kinetik (eecd46d3d3)
- bug 1230377 - part 1/2: ensure nsKeyObject releases NSS resources on shutdown r=jcj (9ceefecbea)
- bug 1230377 - part 2/2: simplify nsIKeyObject and nsIKeyObjectFactory r=jcj (1297d168b7)
- bug 1239609 - audit nsNSSShutDownObject destructors for correctness r=Cykesiopka,sworkman (c78404e52a)
- Bug 1246263 - fix unified build pollution r=valentin (f8db2c45cf)
- Bug 1214981 - Disable output stream buffering. r=keeler (d9e7a1b863)
- bug 1240173 - improve nsIX509Cert.dbKey r=Cykesiopka (0c0fc8e8a3)
- Bug 1238042 - Extract a helper function to check if a JSObject is a global with a particular about: URI. r=ehsan (d065854725)
- Bug 1244118 - Shutdown threadpool when xpcom-shutdown-threads happened. r=roc (e6ef2768b6)
- Bug 1201685 - Limit the number of indexedDB open() calls in IndexedDBHelper r=gwagner (a4fc80fca2)
- Bug 1244049 - Part 3: Replace the type of nsCSSSelector::mPseudoType. r=dbaron (c817ee6145)
- Bug 1244049 - Part 4: Define CSSPseudoElementTypeBase. r=dbaron (94dab59375)
- Bug 1246846 (part 1) - Avoid nsTHashtable::RawRemoveEntry() in dom/.  r=bz. (5371e478da)
- Bug 1246846 (part 2) - Avoid nsTHashtable::RawRemoveEntry() in nsPermissionManager. r=mconnor. (d7a1143ed1)
- Bug 1246846 (part 3) - Avoid nsTHashtable::RawRemoveEntry() in gfxFontconfigUtils. r=jfkthame. (d23259ca8e)
- Bug 1246846 (part 4) - Avoid nsTHashtable::RawRemoveEntry() in FramePropertyTable. r=roc. (7de416abfa)
- Bug 1238404 - Use 'using' directive instead of having separate Dispatch impl in subclasses of nsIEventTarget. r=froydnj (43028ed3b3)
- Bug 938699 - Remove FindElementWithViewId from nsIDOMWindowUtils.idl and nsDOMWindowUtils.cpp. r=kats (b49d2b5e6a)
- missing bit of Bug 1210294 - Remove the release-mode IsCallerChrome assertions (a555243280)
This commit is contained in:
2023-11-22 17:12:24 +08:00
parent 41439a0592
commit dcf4178212
307 changed files with 15145 additions and 3072 deletions
+7 -7
View File
@@ -1059,13 +1059,13 @@ GetAccessibleWrap(AtkObject* aAtkObj)
NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
nullptr);
uintptr_t accWrapPtr = isMAIObject ?
MAI_ATK_OBJECT(aAtkObj)->accWrap.Bits() :
reinterpret_cast<uintptr_t>(MAI_ATK_SOCKET(aAtkObj)->accWrap);
if (accWrapPtr & IS_PROXY)
return nullptr;
AccessibleWrap* accWrap = reinterpret_cast<AccessibleWrap*>(accWrapPtr);
AccessibleWrap* accWrap = nullptr;
if (isMAIObject) {
Accessible* acc = MAI_ATK_OBJECT(aAtkObj)->accWrap.AsAccessible();
accWrap = static_cast<AccessibleWrap*>(acc);
} else {
accWrap = MAI_ATK_SOCKET(aAtkObj)->accWrap;
}
// Check if the accessible was deconstructed.
if (!accWrap)
+4 -3
View File
@@ -52,6 +52,7 @@ if CONFIG['MOZ_ENABLE_DBUS']:
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['CLANG_CXX']:
# Suppress clang warning about unused function from gobject's RTTI macros.
CXXFLAGS += ['-Wno-unused-function']
if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
# Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib /
# gobject headers. See bug 1243331 comment 3.
CXXFLAGS += ['-Wno-unused-local-typedefs']
+2
View File
@@ -49,6 +49,8 @@ public:
return 0;
// Convert the scoped enum into an integer while adding it to hash.
// Note: CSSPseudoElementTypeBase is uint8_t, so we convert it into
// uint8_t directly to avoid including the header.
return mozilla::HashGeneric(aKey->mElement,
static_cast<uint8_t>(aKey->mPseudoType));
}
+2 -31
View File
@@ -5,43 +5,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "js/TypeDecls.h"
#include "nsGlobalWindow.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
#include "nsString.h"
#include "xpcpublic.h"
#include "nsContentUtils.h"
namespace mozilla {
struct FeedWriterEnabled {
static bool IsEnabled(JSContext* cx, JSObject* aGlobal)
{
// Make sure the global is a window
nsGlobalWindow* win = xpc::WindowGlobalOrNull(aGlobal);
if (!win) {
return false;
}
// Make sure that the principal is about:feeds.
nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal();
NS_ENSURE_TRUE(principal, false);
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
if (!uri) {
return false;
}
// First check the scheme to avoid getting long specs in the common case.
bool isAbout = false;
uri->SchemeIs("about", &isAbout);
if (!isAbout) {
return false;
}
// Now check the spec itself
nsAutoCString spec;
uri->GetSpec(spec);
return spec.EqualsLiteral("about:feeds");
return nsContentUtils::IsSpecificAboutPage(aGlobal, "about:feeds");
}
};
+35 -3
View File
@@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ImageEncoder.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
@@ -496,6 +495,38 @@ ImageEncoder::GetImageEncoder(nsAString& aType)
return encoder.forget();
}
class EncoderThreadPoolTerminator final : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_IMETHODIMP Observe(nsISupports *, const char *topic, const char16_t *) override
{
NS_ASSERTION(!strcmp(topic, "xpcom-shutdown-threads"),
"Unexpected topic");
if (ImageEncoder::sThreadPool) {
ImageEncoder::sThreadPool->Shutdown();
ImageEncoder::sThreadPool = nullptr;
}
return NS_OK;
}
private:
~EncoderThreadPoolTerminator() {}
};
NS_IMPL_ISUPPORTS(EncoderThreadPoolTerminator, nsIObserver)
static void
RegisterEncoderThreadPoolTerminatorObserver()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
NS_ASSERTION(os, "do_GetService failed");
os->AddObserver(new EncoderThreadPoolTerminator(),
"xpcom-shutdown-threads",
false);
}
/* static */
nsresult
ImageEncoder::EnsureThreadPool()
@@ -503,12 +534,13 @@ ImageEncoder::EnsureThreadPool()
if (!sThreadPool) {
nsCOMPtr<nsIThreadPool> threadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
sThreadPool = threadPool;
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
ClearOnShutdown(&sThreadPool);
RegisterEncoderThreadPoolTerminatorObserver();
}));
} else {
ClearOnShutdown(&sThreadPool);
RegisterEncoderThreadPoolTerminatorObserver();
}
const uint32_t kThreadLimit = 2;
+1
View File
@@ -114,6 +114,7 @@ private:
static StaticRefPtr<nsIThreadPool> sThreadPool;
friend class EncodingRunnable;
friend class EncoderThreadPoolTerminator;
};
/**
+31 -11
View File
@@ -4,8 +4,8 @@
"use strict";
let DEBUG = 0;
let debug;
var DEBUG = 0;
var debug;
if (DEBUG) {
debug = function (s) { dump("-*- IndexedDBHelper: " + s + "\n"); }
} else {
@@ -24,13 +24,10 @@ Cu.importGlobalProperties(["indexedDB"]);
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
'resource://gre/modules/Services.jsm');
this.IndexedDBHelper = function IndexedDBHelper() {}
this.IndexedDBHelper = function IndexedDBHelper() {
}
IndexedDBHelper.prototype = {
// Cache the database
_db: null,
// Close the database
close: function close() {
if (this._db) {
@@ -48,8 +45,22 @@ IndexedDBHelper.prototype = {
* @param failureCb
* Error callback to call when an error is encountered.
*/
open: function open(aSuccessCb, aFailureCb) {
open: function open(aCallback) {
if (aCallback && !this._waitForOpenCallbacks.has(aCallback)) {
this._waitForOpenCallbacks.add(aCallback);
if (this._waitForOpenCallbacks.size !== 1) {
return;
}
}
let self = this;
let invokeCallbacks = err => {
for (let callback of self._waitForOpenCallbacks) {
callback(err);
}
self._waitForOpenCallbacks.clear();
};
if (DEBUG) debug("Try to open database:" + self.dbName + " " + self.dbVersion);
let req = indexedDB.open(this.dbName, this.dbVersion);
req.onsuccess = function (event) {
@@ -58,7 +69,7 @@ IndexedDBHelper.prototype = {
self._db.onversionchange = function(event) {
if (DEBUG) debug("WARNING: DB modified from a different window.");
}
aSuccessCb && aSuccessCb();
invokeCallbacks();
};
req.onupgradeneeded = function (aEvent) {
@@ -72,7 +83,7 @@ IndexedDBHelper.prototype = {
};
req.onerror = function (aEvent) {
if (DEBUG) debug("Failed to open database: " + self.dbName);
aFailureCb && aFailureCb(aEvent.target.error.name);
invokeCallbacks(aEvent.target.error.name);
};
req.onblocked = function (aEvent) {
if (DEBUG) debug("Opening database request is blocked.");
@@ -96,7 +107,13 @@ IndexedDBHelper.prototype = {
}
return;
}
this.open(aSuccessCb, aFailureCb);
this.open(aError => {
if (aError) {
aFailureCb && aFailureCb(aError);
} else {
aSuccessCb && aSuccessCb();
}
});
},
/**
@@ -169,5 +186,8 @@ IndexedDBHelper.prototype = {
this.dbName = aDBName;
this.dbVersion = aDBVersion;
this.dbStoreNames = aDBStoreNames;
// Cache the database.
this._db = null;
this._waitForOpenCallbacks = new Set();
}
}
+1 -1
View File
@@ -219,7 +219,7 @@ ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
if (entry) {
entry->RemoveIdElement(aElement);
if (entry->IsEmpty()) {
mIdentifierMap.RawRemoveEntry(entry);
mIdentifierMap.RemoveEntry(entry);
}
}
}
+1 -4
View File
@@ -81,10 +81,7 @@ public:
NS_DECL_NSIREQUEST
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
using nsIEventTarget::Dispatch;
explicit WebSocketImpl(WebSocket* aWebSocket)
: mWebSocket(aWebSocket)
+34
View File
@@ -8920,3 +8920,37 @@ nsContentUtils::SerializeNodeToMarkup(nsINode* aRoot,
}
}
}
bool
nsContentUtils::IsSpecificAboutPage(JSObject* aGlobal, const char* aUri)
{
// aUri must start with about: or this isn't the right function to be using.
MOZ_ASSERT(strncmp(aUri, "about:", 6) == 0);
// Make sure the global is a window
nsGlobalWindow* win = xpc::WindowGlobalOrNull(aGlobal);
if (!win) {
return false;
}
// Make sure that the principal is about:feeds.
nsCOMPtr<nsIPrincipal> principal = win->GetPrincipal();
NS_ENSURE_TRUE(principal, false);
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
if (!uri) {
return false;
}
// First check the scheme to avoid getting long specs in the common case.
bool isAbout = false;
uri->SchemeIs("about", &isAbout);
if (!isAbout) {
return false;
}
// Now check the spec itself
nsAutoCString spec;
uri->GetSpec(spec);
return spec.EqualsASCII(aUri);
}
+8
View File
@@ -2600,6 +2600,14 @@ public:
bool aDescendentsOnly,
nsAString& aOut);
/*
* Returns true iff the provided JSObject is a global, and its URI matches
* the provided about: URI.
* @param aGlobal the JSObject whose URI to check, if it is a global.
* @param aUri the URI to match, e.g. "about:feeds"
*/
static bool IsSpecificAboutPage(JSObject* aGlobal, const char* aUri);
private:
static bool InitializeEventTable();
-12
View File
@@ -1821,16 +1821,6 @@ nsDOMWindowUtils::GetFocusedInputType(char** aType)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::FindElementWithViewId(nsViewID aID,
nsIDOMElement** aResult)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
RefPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aID);
return content ? CallQueryInterface(content, aResult) : NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetViewId(nsIDOMElement* aElement, nsViewID* aResult)
{
@@ -2623,8 +2613,6 @@ nsDOMWindowUtils::ComputeAnimationDistance(nsIDOMElement* aElement,
const nsAString& aValue2,
double* aResult)
{
MOZ_RELEASE_ASSERT(nsContentUtils::LegacyIsCallerChromeOrNativeCode());
nsresult rv;
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
NS_ENSURE_SUCCESS(rv, rv);
+1 -1
View File
@@ -3052,7 +3052,7 @@ nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
++mExpandoAndGeneration.generation;
}
if (entry->IsEmpty()) {
mIdentifierMap.RawRemoveEntry(entry);
mIdentifierMap.RemoveEntry(entry);
}
}
@@ -18,9 +18,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
var file = location.href;
var asyncFrame;
/* Async parent frames from pushPrefEnv don't show up in e10s. */
var isE10S = !SpecialPowers.Services.wm.getMostRecentWindow("navigator:browser");
var isE10S = !SpecialPowers.isMainProcess();
if (!isE10S && SpecialPowers.getBoolPref("javascript.options.asyncstack")) {
asyncFrame = `Async*@${file}:153:1
asyncFrame = `Async*@${file}:153:3
`;
} else {
asyncFrame = "";
@@ -38,10 +38,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
function doTest() {
var t = new TestInterfaceJS();
/* Async parent frames from pushPrefEnv don't show up in e10s. */
var isE10S = !SpecialPowers.Services.wm.getMostRecentWindow("navigator:browser");
var isE10S = !SpecialPowers.isMainProcess();
var asyncStack = SpecialPowers.getBoolPref("javascript.options.asyncstack");
var ourFile = location.href;
var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:121:1
var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:121:3
` : "";
Promise.all([
@@ -1480,13 +1480,6 @@ interface nsIDOMWindowUtils : nsISupports {
*/
readonly attribute string focusedInputType;
/**
* Given a view ID from the compositor process, retrieve the element
* associated with a view. For scrollpanes for documents, the root
* element of the document is returned.
*/
nsIDOMElement findElementWithViewId(in nsViewID aId);
/**
* Find the view ID for a given element. This is the reverse of
* findElementWithViewId().
+14 -2
View File
@@ -163,17 +163,29 @@ CanCreateWMFDecoder()
return result.value();
}
/* static */ bool
WMFDecoderModule::HasH264()
{
return CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>();
}
/* static */ bool
WMFDecoderModule::HasAAC()
{
return CanCreateWMFDecoder<CLSID_CMSAACDecMFT>();
}
bool
WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType) const
{
if ((aMimeType.EqualsLiteral("audio/mp4a-latm") ||
aMimeType.EqualsLiteral("audio/mp4")) &&
CanCreateWMFDecoder<CLSID_CMSAACDecMFT>()) {
WMFDecoderModule::HasAAC()) {
return true;
}
if ((aMimeType.EqualsLiteral("video/avc") ||
aMimeType.EqualsLiteral("video/mp4")) &&
CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>()) {
WMFDecoderModule::HasH264()) {
return true;
}
if (aMimeType.EqualsLiteral("audio/mpeg") &&
@@ -42,6 +42,15 @@ public:
// Called from any thread, must call init first
static int GetNumDecoderThreads();
static bool LowLatencyMFTEnabled();
// Accessors that report whether we have the required MFTs available
// on the system to play various codecs. Windows Vista doesn't have the
// H.264/AAC decoders if the "Platform Update Supplement for Windows Vista"
// is not installed, and Window N and KN variants also require a "Media
// Feature Pack" to be installed. Windows XP doesn't have WMF.
static bool HasAAC();
static bool HasH264();
private:
bool mWMFInitialized;
};
+6
View File
@@ -439,6 +439,12 @@ WifiCertService::WifiCertService()
WifiCertService::~WifiCertService()
{
MOZ_ASSERT(!gWifiCertService);
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return;
}
shutdown(calledFromObject);
}
already_AddRefed<WifiCertService>
+1 -1
View File
@@ -1831,7 +1831,7 @@ XULDocument::RemoveElementFromRefMap(Element* aElement)
if (!entry)
return;
if (entry->RemoveElement(aElement)) {
mRefMap.RawRemoveEntry(entry);
mRefMap.RemoveEntry(entry);
}
}
}
+2 -2
View File
@@ -794,7 +794,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
PermissionHashKey* entry = mPermissionTable.PutEntry(key);
if (!entry) return NS_ERROR_FAILURE;
if (!entry->GetKey()) {
mPermissionTable.RawRemoveEntry(entry);
mPermissionTable.RemoveEntry(entry);
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -929,7 +929,7 @@ nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
// If there are no more permissions stored for that entry, clear it.
if (entry->GetPermissions().IsEmpty()) {
mPermissionTable.RawRemoveEntry(entry);
mPermissionTable.RemoveEntry(entry);
}
break;
+4 -4
View File
@@ -617,13 +617,13 @@ gfxFontconfigUtils::UpdateFontListInternal(bool aForce)
bool added = entry->AddFont(font);
if (!entry->mKey) {
// The reference to the font pattern keeps the pointer to
// string for the key valid. If adding the font failed
// then the entry must be removed.
// The reference to the font pattern keeps the pointer
// to string for the key valid. If adding the font
// failed then the entry must be removed.
if (added) {
entry->mKey = family;
} else {
mFontsByFamily.RawRemoveEntry(entry);
mFontsByFamily.RemoveEntry(entry);
}
}
}
+1 -4
View File
@@ -81,10 +81,7 @@
#elif defined(__ppc__) || defined(__powerpc__)
#define ARCH_CPU_PPC 1
#define ARCH_CPU_32_BITS 1
#elif defined(__m68k__)
#define ARCH_CPU_M68K 1
#define ARCH_CPU_32_BITS 1
#elif defined(__sparc__) && defined(__arch64__)
#elif defined(__sparc64__)
#define ARCH_CPU_SPARC 1
#define ARCH_CPU_64_BITS 1
#elif defined(__sparc__)
+3 -2
View File
@@ -166,10 +166,11 @@ struct ClassInfo
#define FOR_EACH_SIZE(macro) \
macro(Objects, GCHeapUsed, objectsGCHeap) \
macro(Objects, MallocHeap, objectsMallocHeapSlots) \
macro(Objects, MallocHeap, objectsMallocHeapElementsNonAsmJS) \
macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
macro(Objects, NonHeap, objectsNonHeapElementsNormal) \
macro(Objects, NonHeap, objectsNonHeapElementsAsmJS) \
macro(Objects, NonHeap, objectsNonHeapElementsMapped) \
macro(Objects, NonHeap, objectsNonHeapElementsShared) \
macro(Objects, NonHeap, objectsNonHeapCodeAsmJS) \
macro(Objects, MallocHeap, objectsMallocHeapMisc) \
\
+63 -5
View File
@@ -109,7 +109,7 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global)
}
/* static */ ImportEntryObject*
ImportEntryObject::create(JSContext* cx,
ImportEntryObject::create(ExclusiveContext* cx,
HandleAtom moduleRequest,
HandleAtom importName,
HandleAtom localName)
@@ -181,7 +181,7 @@ StringOrNullValue(JSString* maybeString)
}
/* static */ ExportEntryObject*
ExportEntryObject::create(JSContext* cx,
ExportEntryObject::create(ExclusiveContext* cx,
HandleAtom maybeExportName,
HandleAtom maybeModuleRequest,
HandleAtom maybeImportName,
@@ -691,6 +691,62 @@ ModuleObject::initImportExportData(HandleArrayObject requestedModules,
initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries));
}
static bool
FreezeObjectProperty(JSContext* cx, HandleNativeObject obj, uint32_t slot)
{
RootedObject property(cx, &obj->getSlot(slot).toObject());
return FreezeObject(cx, property);
}
/* static */ bool
ModuleObject::FreezeArrayProperties(JSContext* cx, HandleModuleObject self)
{
return FreezeObjectProperty(cx, self, RequestedModulesSlot) &&
FreezeObjectProperty(cx, self, ImportEntriesSlot) &&
FreezeObjectProperty(cx, self, LocalExportEntriesSlot) &&
FreezeObjectProperty(cx, self, IndirectExportEntriesSlot) &&
FreezeObjectProperty(cx, self, StarExportEntriesSlot);
}
static inline void
AssertObjectPropertyFrozen(JSContext* cx, HandleNativeObject obj, uint32_t slot)
{
#ifdef DEBUG
bool frozen = false;
RootedObject property(cx, &obj->getSlot(slot).toObject());
MOZ_ALWAYS_TRUE(TestIntegrityLevel(cx, property, IntegrityLevel::Frozen, &frozen));
MOZ_ASSERT(frozen);
#endif
}
/* static */ inline void
ModuleObject::AssertArrayPropertiesFrozen(JSContext* cx, HandleModuleObject self)
{
AssertObjectPropertyFrozen(cx, self, RequestedModulesSlot);
AssertObjectPropertyFrozen(cx, self, ImportEntriesSlot);
AssertObjectPropertyFrozen(cx, self, LocalExportEntriesSlot);
AssertObjectPropertyFrozen(cx, self, IndirectExportEntriesSlot);
AssertObjectPropertyFrozen(cx, self, StarExportEntriesSlot);
}
inline static void
AssertModuleScopesMatch(ModuleObject* module)
{
MOZ_ASSERT(IsStaticGlobalLexicalScope(module->enclosingStaticScope()));
MOZ_ASSERT(module->initialEnvironment().enclosingScope().as<ClonedBlockObject>().staticScope() ==
module->enclosingStaticScope());
}
void
ModuleObject::fixScopesAfterCompartmentMerge(JSContext* cx)
{
AssertModuleScopesMatch(this);
Rooted<ClonedBlockObject*> lexicalScope(cx, &script()->global().lexicalScope());
setReservedSlot(StaticScopeSlot, ObjectValue(lexicalScope->staticBlock()));
initialEnvironment().setEnclosingScope(lexicalScope);
AssertModuleScopesMatch(this);
}
bool
ModuleObject::hasScript() const
{
@@ -762,6 +818,8 @@ ModuleObject::noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, Han
/* static */ bool
ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self)
{
AssertArrayPropertiesFrozen(cx, self);
FunctionDeclarationVector* funDecls = self->functionDeclarations();
if (!funDecls) {
JS_ReportError(cx, "Module function declarations have already been instantiated");
@@ -798,6 +856,8 @@ ModuleObject::setEvaluated()
/* static */ bool
ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval)
{
AssertArrayPropertiesFrozen(cx, self);
RootedScript script(cx, self->script());
RootedModuleEnvironmentObject scope(cx, self->environment());
if (!scope) {
@@ -887,7 +947,7 @@ js::InitModuleClasses(JSContext* cx, HandleObject obj)
///////////////////////////////////////////////////////////////////////////
// ModuleBuilder
ModuleBuilder::ModuleBuilder(JSContext* cx, HandleModuleObject module)
ModuleBuilder::ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module)
: cx_(cx),
module_(cx, module),
requestedModules_(cx, AtomVector(cx)),
@@ -1170,8 +1230,6 @@ ArrayObject* ModuleBuilder::createArray(const GCVector<T>& vector)
array->setDenseInitializedLength(length);
for (uint32_t i = 0; i < length; i++)
array->initDenseElement(i, MakeElementValue(vector[i]));
if (!JS_FreezeObject(cx_, array))
return nullptr;
return array;
}
+9 -6
View File
@@ -43,9 +43,9 @@ class ImportEntryObject : public NativeObject
};
static const Class class_;
static JSObject* initClass(JSContext* cx, HandleObject obj);
static JSObject* initClass(ExclusiveContext* cx, HandleObject obj);
static bool isInstance(HandleValue value);
static ImportEntryObject* create(JSContext* cx,
static ImportEntryObject* create(ExclusiveContext* cx,
HandleAtom moduleRequest,
HandleAtom importName,
HandleAtom localName);
@@ -70,9 +70,9 @@ class ExportEntryObject : public NativeObject
};
static const Class class_;
static JSObject* initClass(JSContext* cx, HandleObject obj);
static JSObject* initClass(ExclusiveContext* cx, HandleObject obj);
static bool isInstance(HandleValue value);
static ExportEntryObject* create(JSContext* cx,
static ExportEntryObject* create(ExclusiveContext* cx,
HandleAtom maybeExportName,
HandleAtom maybeModuleRequest,
HandleAtom maybeImportName,
@@ -232,6 +232,9 @@ class ModuleObject : public NativeObject
HandleArrayObject localExportEntries,
HandleArrayObject indiretExportEntries,
HandleArrayObject starExportEntries);
static bool FreezeArrayProperties(JSContext* cx, HandleModuleObject self);
static void AssertArrayPropertiesFrozen(JSContext* cx, HandleModuleObject self);
void fixScopesAfterCompartmentMerge(JSContext* cx);
JSScript* script() const;
JSObject* enclosingStaticScope() const;
@@ -273,7 +276,7 @@ class ModuleObject : public NativeObject
class MOZ_STACK_CLASS ModuleBuilder
{
public:
explicit ModuleBuilder(JSContext* cx, HandleModuleObject module);
explicit ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module);
bool processImport(frontend::ParseNode* pn);
bool processExport(frontend::ParseNode* pn);
@@ -296,7 +299,7 @@ class MOZ_STACK_CLASS ModuleBuilder
using RootedImportEntryVector = JS::Rooted<ImportEntryVector>;
using RootedExportEntryVector = JS::Rooted<ExportEntryVector>;
JSContext* cx_;
ExclusiveContext* cx_;
RootedModuleObject module_;
RootedAtomVector requestedModules_;
RootedAtomVector importedBoundNames_;
+190 -19
View File
@@ -6,12 +6,158 @@
// consolidated here to avoid confusion and re-implementation of existing
// algorithms.
// For sorting values with limited range; uint8 and int8.
function CountingSort(array, len, signed) {
var buffer = new List();
var min = 0;
// Map int8 values onto the uint8 range when storing in buffer.
if (signed) {
min = -128;
}
for (var i = 0; i < 256; i++) {
buffer[i] = 0;
}
// Populate the buffer
for (var i = 0; i < len; i++) {
var val = array[i];
buffer[val - min]++
}
// Traverse the buffer in order and write back elements to array
var val = 0;
for (var i = 0; i < len; i++) {
// Invariant: sum(buffer[val:]) == len-i
while (true) {
if (buffer[val] > 0) {
array[i] = val + min;
buffer[val]--;
break;
} else {
val++;
}
}
}
return array;
}
// Helper for RadixSort
function ByteAtCol(x, pos) {
return (x >> (pos * 8)) & 0xFF;
}
function SortByColumn(array, len, aux, col) {
const R = 256;
let counts = new List();
// |counts| is used to compute the starting index position for each key.
// Letting counts[0] always be 0, simplifies the transform step below.
// Example:
//
// Computing frequency counts for the input [1 2 1] gives:
// 0 1 2 3 ... (keys)
// 0 0 2 1 (frequencies)
//
// Transforming frequencies to indexes gives:
// 0 1 2 3 ... (keys)
// 0 0 2 3 (indexes)
for (let r = 0; r < R + 1; r++) {
counts[r] = 0;
}
// Compute frequency counts
for (let i = 0; i < len; i++) {
let val = array[i];
let b = ByteAtCol(val, col);
counts[b + 1]++;
}
// Transform counts to indices.
for (let r = 0; r < R; r++) {
counts[r+1] += counts[r];
}
// Distribute
for (let i = 0; i < len; i++) {
let val = array[i];
let b = ByteAtCol(val, col);
aux[counts[b]++] = val;
}
// Copy back
for (let i = 0; i < len; i++) {
array[i] = aux[i];
}
}
// Sorts integers and float32. |signed| is true for int16 and int32, |floating|
// is true for float32.
function RadixSort(array, len, nbytes, signed, floating, comparefn) {
// Determined by performance testing.
if (len < 128) {
QuickSort(array, len, comparefn);
return array;
}
let aux = new List();
for (let i = 0; i < len; i++) {
aux[i] = 0;
}
let view = array;
let signMask = 1 << nbytes * 8 - 1;
// Preprocess
if (floating) {
view = new Int32Array(array.buffer);
// Flip sign bit for positive numbers; flip all bits for negative
// numbers
for (let i = 0; i < len; i++) {
if (view[i] & signMask) {
view[i] ^= 0xFFFFFFFF;
} else {
view[i] ^= signMask
}
}
} else if (signed) {
// Flip sign bit
for (let i = 0; i < len; i++) {
view[i] ^= signMask
}
}
// Sort
for (let col = 0; col < nbytes; col++) {
SortByColumn(view, len, aux, col);
}
// Restore original bit representation
if (floating) {
for (let i = 0; i < len; i++) {
if (view[i] & signMask) {
view[i] ^= signMask;
} else {
view[i] ^= 0xFFFFFFFF;
}
}
} else if (signed) {
for (let i = 0; i < len; i++) {
view[i] ^= signMask
}
}
return array;
}
// For sorting small arrays.
function InsertionSort(array, from, to, comparefn) {
var item, swap;
for (var i = from + 1; i <= to; i++) {
let item, swap, i, j;
for (i = from + 1; i <= to; i++) {
item = array[i];
for (var j = i - 1; j >= from; j--) {
for (j = i - 1; j >= from; j--) {
swap = array[j];
if (comparefn(swap, item) <= 0)
break;
@@ -28,28 +174,29 @@ function SwapArrayElements(array, i, j) {
}
// A helper function for MergeSort.
function Merge(array, start, mid, end, lBuffer, rBuffer, comparefn) {
function Merge(list, start, mid, end, lBuffer, rBuffer, comparefn) {
var i, j, k;
var sizeLeft = mid - start + 1;
var sizeRight = end - mid;
// Copy our virtual arrays into separate buffers.
// Copy our virtual lists into separate buffers.
for (i = 0; i < sizeLeft; i++)
lBuffer[i] = array[start + i];
lBuffer[i] = list[start + i];
for (j = 0; j < sizeRight; j++)
rBuffer[j] = array[mid + 1 + j];
rBuffer[j] = list[mid + 1 + j];
i = 0;
j = 0;
k = start;
while (i < sizeLeft && j < sizeRight) {
if (comparefn(lBuffer[i], rBuffer[j]) <= 0) {
array[k] = lBuffer[i];
list[k] = lBuffer[i];
i++;
} else {
array[k] = rBuffer[j];
list[k] = rBuffer[j];
j++;
}
k++;
@@ -57,46 +204,70 @@ function Merge(array, start, mid, end, lBuffer, rBuffer, comparefn) {
// Empty out any remaining elements in the buffer.
while (i < sizeLeft) {
array[k] = lBuffer[i];
list[k] =lBuffer[i];
i++;
k++;
}
while (j < sizeRight) {
array[k] = rBuffer[j];
list[k] =rBuffer[j];
j++;
k++;
}
}
// Helper function for overwriting a sparse array with a
// dense array, filling remaining slots with holes.
function MoveHoles(sparse, sparseLen, dense, denseLen) {
for (var i = 0; i < denseLen; i++)
_DefineDataProperty(sparse, i, dense[i]);
for (var j = denseLen; j < sparseLen; j++)
delete sparse[j];
}
// Iterative, bottom up, mergesort.
function MergeSort(array, len, comparefn) {
// To save effort we will do all of our work on a dense list,
// then create holes at the end.
var denseList = new List();
var denseLen = 0;
for (var i = 0; i < len; i++) {
if (i in array)
denseList[denseLen++] = array[i];
}
if (denseLen < 1)
return array;
// Insertion sort for small arrays, where "small" is defined by performance
// testing.
if (len < 24) {
InsertionSort(array, 0, len - 1, comparefn);
return array;
InsertionSort(denseList, 0, denseLen - 1, comparefn);
MoveHoles(array, len, denseList, denseLen);
return array;
}
// We do all of our allocating up front
var lBuffer = new List();
var rBuffer = new List();
var mid, end, endOne, endTwo;
for (var windowSize = 1; windowSize < len; windowSize = 2*windowSize) {
for (var start = 0; start < len - 1; start += 2*windowSize) {
assert(windowSize < len, "The window size is larger than the array length!");
var mid, end, endOne, endTwo;
for (var windowSize = 1; windowSize < denseLen; windowSize = 2 * windowSize) {
for (var start = 0; start < denseLen - 1; start += 2 * windowSize) {
assert(windowSize < denseLen, "The window size is larger than the array denseLength!");
// The midpoint between the two subarrays.
mid = start + windowSize - 1;
// To keep from going over the edge.
end = start + 2 * windowSize - 1;
end = end < len - 1 ? end : len - 1;
end = end < denseLen - 1 ? end : denseLen - 1;
// Skip lopsided runs to avoid doing useless work
if (mid > end)
continue;
Merge(array, start, mid, end, lBuffer, rBuffer, comparefn);
Merge(denseList, start, mid, end, lBuffer, rBuffer, comparefn);
}
}
MoveHoles(array, len, denseList, denseLen);
return array;
}
+16 -1
View File
@@ -988,7 +988,22 @@ function TypedArraySort(comparefn) {
if (comparefn === undefined) {
comparefn = TypedArrayCompare;
} else {
// CountingSort doesn't invoke the comparefn
if (IsUint8TypedArray(obj)) {
return CountingSort(obj, len, false /* signed */);
} else if (IsInt8TypedArray(obj)) {
return CountingSort(obj, len, true /* signed */);
} else if (IsUint16TypedArray(obj)) {
return RadixSort(obj, len, 2 /* nbytes */, false /* signed */, false /* floating */, comparefn);
} else if (IsInt16TypedArray(obj)) {
return RadixSort(obj, len, 2 /* nbytes */, true /* signed */, false /* floating */, comparefn);
} else if (IsUint32TypedArray(obj)) {
return RadixSort(obj, len, 4 /* nbytes */, false /* signed */, false /* floating */, comparefn);
} else if (IsInt32TypedArray(obj)) {
return RadixSort(obj, len, 4 /* nbytes */, true /* signed */, false /* floating */, comparefn);
} else if (IsFloat32TypedArray(obj)) {
return RadixSort(obj, len, 4 /* nbytes */, true /* signed */, true /* floating */, comparefn);
}
// To satisfy step 2 from TypedArray SortCompare described in 22.2.3.26
// the user supplied comparefn is wrapped.
var wrappedCompareFn = comparefn;
+10
View File
@@ -536,3 +536,13 @@ other kinds of objects.
`TypeError`. Determine which global is designated by <i>global</i>
using the same rules as [`Debugger.prototype.addDebuggee`][add].
## Static methods of the Debugger Object
The functions described below are not called with a `this` value.
<code id="isCompilableUnit">isCompilableUnit(<i>source</i>)</code>
: Given a string of source code, designated by <i>source</i>, return false if
the string might become a valid JavaScript statement with the addition of
more lines. Otherwise return true. The intent is to support interactive
compilation - accumulate lines in a buffer until isCompilableUnit is true,
then pass it to the compiler.
+18 -6
View File
@@ -576,7 +576,7 @@ ModuleObject* BytecodeCompiler::compileModule()
module->init(script);
ModuleBuilder builder(cx->asJSContext(), module);
ModuleBuilder builder(cx, module);
ParseNode* pn = parser->standaloneModule(module, builder);
if (!pn)
return nullptr;
@@ -759,20 +759,32 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
}
ModuleObject*
frontend::CompileModule(JSContext* cx, HandleObject obj,
const ReadOnlyCompileOptions& optionsInput,
SourceBufferHolder& srcBuf)
frontend::CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& optionsInput,
SourceBufferHolder& srcBuf, LifoAlloc* alloc)
{
MOZ_ASSERT(srcBuf.get());
MOZ_ASSERT(cx->isJSContext() == (alloc == nullptr));
if (!alloc)
alloc = &cx->asJSContext()->tempLifoAlloc();
CompileOptions options(cx, optionsInput);
options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code.
options.setIsRunOnce(true);
Rooted<StaticScope*> staticScope(cx, &cx->global()->lexicalScope().staticBlock());
BytecodeCompiler compiler(cx, &cx->tempLifoAlloc(), options, srcBuf, staticScope,
BytecodeCompiler compiler(cx, alloc, options, srcBuf, staticScope,
TraceLogger_ParserCompileModule);
return compiler.compileModule();
RootedModuleObject module(cx, compiler.compileModule());
if (!module)
return nullptr;
// This happens in GlobalHelperThreadState::finishModuleParseTask() when a
// module is compiled off main thread.
if (cx->isJSContext() && !ModuleObject::FreezeArrayProperties(cx->asJSContext(), module))
return nullptr;
return module;
}
bool
+3 -3
View File
@@ -32,9 +32,9 @@ CompileScript(ExclusiveContext* cx, LifoAlloc* alloc,
SourceCompressionTask* extraSct = nullptr,
ScriptSourceObject** sourceObjectOut = nullptr);
ModuleObject *
CompileModule(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
SourceBufferHolder &srcBuf);
ModuleObject*
CompileModule(ExclusiveContext *cx, const ReadOnlyCompileOptions &options,
SourceBufferHolder &srcBuf, LifoAlloc* alloc = nullptr);
bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
+6 -5
View File
@@ -128,7 +128,7 @@ struct Zone : public JS::shadow::Zone,
{
explicit Zone(JSRuntime* rt);
~Zone();
bool init(bool isSystem);
MOZ_WARN_UNUSED_RESULT bool init(bool isSystem);
void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone>& finder);
@@ -152,7 +152,8 @@ struct Zone : public JS::shadow::Zone,
bool isTooMuchMalloc() const { return gcMallocBytes <= 0; }
void onTooMuchMalloc();
void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
MOZ_WARN_UNUSED_RESULT void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes,
void* reallocPtr = nullptr) {
if (!js::CurrentThreadCanAccessRuntime(runtime_))
return nullptr;
return runtimeFromMainThread()->onOutOfMemory(allocFunc, nbytes, reallocPtr);
@@ -360,7 +361,7 @@ struct Zone : public JS::shadow::Zone,
mozilla::DebugOnly<unsigned> gcLastZoneGroupIndex;
// Creates a HashNumber based on getUniqueId. Returns false on OOM.
bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) {
MOZ_WARN_UNUSED_RESULT bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) {
uint64_t uid;
if (!getUniqueId(cell, &uid))
return false;
@@ -370,7 +371,7 @@ struct Zone : public JS::shadow::Zone,
// Puts an existing UID in |uidp|, or creates a new UID for this Cell and
// puts that into |uidp|. Returns false on OOM.
bool getUniqueId(js::gc::Cell* cell, uint64_t* uidp) {
MOZ_WARN_UNUSED_RESULT bool getUniqueId(js::gc::Cell* cell, uint64_t* uidp) {
MOZ_ASSERT(uidp);
MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
@@ -396,7 +397,7 @@ struct Zone : public JS::shadow::Zone,
}
// Return true if this cell has a UID associated with it.
bool hasUniqueId(js::gc::Cell* cell) {
MOZ_WARN_UNUSED_RESULT bool hasUniqueId(js::gc::Cell* cell) {
MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
return uniqueIds_.has(cell);
}
@@ -2,12 +2,9 @@
load(libdir + "asserts.js");
function argsobj() { return arguments; }
var misc = [
{}, {x: 1}, Math, isNaN,
Object.create(null),
argsobj(0, 1, 2),
true, 0, 3.1416,
new Boolean(true), new Number(0),
{iterator: function () { return undefined; }},
@@ -19,4 +16,4 @@ var misc = [
for (var v of misc) {
assertThrowsInstanceOf(function () { new Set(v); }, TypeError);
assertThrowsInstanceOf(function () { new Map(v); }, TypeError);
}
}
@@ -0,0 +1,58 @@
load(libdir + "asserts.js");
const bad_types = [
2112,
{geddy: "lee"},
() => 1,
[],
Array
]
// We only accept strings around here!
for (var badType of bad_types) {
assertThrowsInstanceOf(() => {
Debugger.isCompilableUnit(badType);
}, TypeError);
}
const compilable_units = [
"wubba-lubba-dub-dub",
"'Get Schwifty!'",
"1 + 2",
"function f(x) {}",
"function x(f,) {", // statements with bad syntax are always compilable
"let x = 100",
";;;;;;;;",
"",
" ",
"\n",
"let x",
]
const non_compilable_units = [
"function f(x) {",
"(...d) =>",
"{geddy:",
"{",
"[1, 2",
"[",
"1 +",
"let x =",
"3 ==",
]
for (var code of compilable_units) {
assertEq(Debugger.isCompilableUnit(code), true);
}
for (var code of non_compilable_units) {
assertEq(Debugger.isCompilableUnit(code), false);
}
// Supplying no arguments should throw a type error
assertThrowsInstanceOf(() => {
Debugger.isCompilableUnit();
}, TypeError);
// Supplying extra arguments should be fine
assertEq(Debugger.isCompilableUnit("", 1, 2, 3, 4, {}, []), true);
@@ -0,0 +1,13 @@
gczeal(2);
g = newGlobal();
dbg = Debugger(g);
function loop() {
for (var i = 0; i < 10; i++)
debugger;
}
g.eval(loop.toSource());
dbg.onDebuggerStatement = function(f) {
f.script.getOffsetsCoverage();
}
dbg.collectCoverageInfo = true;
g.eval("loop")();
@@ -0,0 +1,27 @@
// |jit-test| allow-oom
if (!('oomAfterAllocations' in this))
quit();
if (helperThreadCount() === 0)
quit(0);
lfcode = new Array();
dbg = Debugger();
dbg.onEnterFrame = function() {};
g = newGlobal();
lfcode.push(`
oomAfterAllocations(100);
new Number();
dbg.addDebuggee(g);
`)
file = lfcode.shift();
loadFile(file);
function loadFile(lfVarx) {
lfGlobal = newGlobal()
for (lfLocal in this)
if (!(lfLocal in lfGlobal))
lfGlobal[lfLocal] = this[lfLocal]
offThreadCompileScript(lfVarx)
lfGlobal.runOffThreadScript()
}
+12
View File
@@ -0,0 +1,12 @@
// |jit-test| allow-oom
if (!('oomAfterAllocations' in this))
quit();
var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("(" + function() {
oomAfterAllocations(100);
var dbg = Debugger(debuggeeGlobal);
dbg.onEnterFrame = function(frame) {}
} + ")()");
+24
View File
@@ -0,0 +1,24 @@
// |jit-test| allow-oom
if (!('oomAfterAllocations' in this))
quit();
(function() {
g = newGlobal()
dbg = new Debugger
g.toggle = function(d) {
if (d) {
dbg.addDebuggee(g);
dbg.getNewestFrame();
oomAfterAllocations(2);
setBreakpoint;
}
}
g.eval("" + function f(d) toggle(d))
g.eval("(" + function() {
f(false);
f(true);
} + ")()")
})();
+11
View File
@@ -0,0 +1,11 @@
// |jit-test| allow-oom
if (!('oomAfterAllocations' in this))
quit();
var g = newGlobal();
g.debuggeeGlobal = [];
g.eval("(" + function() {
oomAfterAllocations(57);
Debugger(debuggeeGlobal).onEnterFrame = function() {}
} + ")()");
@@ -2,12 +2,9 @@
load(libdir + "asserts.js");
function argsobj() { return arguments; }
var misc = [
{}, {x: 1}, Math, isNaN,
Object.create(null),
argsobj(0, 1, 2),
null, undefined,
true, 0, 3.1416,
new Boolean(true), new Number(0),
+8
View File
@@ -0,0 +1,8 @@
if (!('oomTest' in this))
quit();
function arrayProtoOutOfRange() {
for (let [] = () => r, get;;)
var r = f(i % 2 ? a : b);
}
oomTest(arrayProtoOutOfRange);
+2 -1
View File
@@ -1,4 +1,4 @@
// |jit-test| error: TypeError
// |jit-test|
function f(c) {
var b = arguments;
if (c == 1)
@@ -9,6 +9,7 @@ function f(c) {
evaluate("f('a', 'b', 'c', 'd', 'e');");
function test(){
var args = f('a', (0), 'c');
var s;
for (var v of args)
s += v;
}
@@ -0,0 +1,32 @@
// Test interaction with global object and global lexical scope.
function parseAndEvaluate(source) {
let m = parseModule(source);
m.declarationInstantiation();
return m.evaluation();
}
var x = 1;
assertEq(parseAndEvaluate("let r = x; x = 2; r"), 1);
assertEq(x, 2);
let y = 3;
assertEq(parseAndEvaluate("let r = y; y = 4; r"), 3);
assertEq(y, 4);
if (helperThreadCount() == 0)
quit();
function offThreadParseAndEvaluate(source) {
offThreadCompileModule(source);
let m = finishOffThreadModule();
print("compiled");
m.declarationInstantiation();
return m.evaluation();
}
assertEq(offThreadParseAndEvaluate("let r = x; x = 5; r"), 2);
assertEq(x, 5);
assertEq(offThreadParseAndEvaluate("let r = y; y = 6; r"), 4);
assertEq(y, 6);
@@ -0,0 +1,16 @@
// Test off thread module compilation.
if (helperThreadCount() == 0)
quit();
load(libdir + "asserts.js");
load(libdir + "dummyModuleResolveHook.js");
function offThreadParseAndEvaluate(source) {
offThreadCompileModule(source);
let m = finishOffThreadModule();
m.declarationInstantiation();
return m.evaluation();
}
offThreadParseAndEvaluate("export let x = 2 * 3;");
@@ -0,0 +1,9 @@
load(libdir + "asserts.js");
assertTypeErrorMessage(() => WeakSet.prototype.add.call({}), "add method called on incompatible Object");
assertTypeErrorMessage(() => newGlobal().WeakSet.prototype.add.call({}), "add method called on incompatible Object");
assertTypeErrorMessage(() => WeakSet.prototype.add.call(15), "add method called on incompatible number");
assertTypeErrorMessage(() => Int8Array.prototype.find.call({}), "find method called on incompatible Object");
assertTypeErrorMessage(() => newGlobal().Int8Array.prototype.find.call({}), "find method called on incompatible Object");
assertTypeErrorMessage(() => Int8Array.prototype.find.call(15), "find method called on incompatible number");
+12 -20
View File
@@ -963,7 +963,8 @@ JS_TransplantObject(JSContext* cx, HandleObject origobj, HandleObject target)
MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
if (!JSObject::swap(cx, origobj, newIdentityWrapper))
MOZ_CRASH();
origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
if (!origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv))
MOZ_CRASH();
}
// The new identity object might be one of several things. Return it to avoid
@@ -1056,15 +1057,6 @@ static const JSStdName builtin_property_names[] = {
#if JS_HAS_UNEVAL
{ EAGER_ATOM(uneval), JSProto_String },
#endif
#ifdef ENABLE_SIMD
{ EAGER_ATOM(SIMD), JSProto_SIMD },
#endif
#ifdef ENABLE_BINARYDATA
{ EAGER_ATOM(TypedObject), JSProto_TypedObject },
#endif
#ifdef ENABLE_SHARED_ARRAY_BUFFER
{ EAGER_ATOM(Atomics), JSProto_Atomics },
#endif
{ 0, JSProto_LIMIT }
};
@@ -1104,14 +1096,8 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso
if (!stdnm)
stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
#ifdef ENABLE_SHARED_ARRAY_BUFFER
if (stdnm && !cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled() &&
(stdnm->atomOffset == NAME_OFFSET(Atomics) ||
stdnm->atomOffset == NAME_OFFSET(SharedArrayBuffer)))
{
if (stdnm && GlobalObject::skipDeselectedConstructor(cx, stdnm->key))
stdnm = nullptr;
}
#endif
// If this class is anonymous, then it doesn't exist as a global
// property, so we won't resolve anything.
@@ -1154,6 +1140,9 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj
JSAtom* atom = JSID_TO_ATOM(id);
// This will return true even for deselected constructors. (To do
// better, we need a JSContext here; it's fine as it is.)
return atom == names.undefined ||
LookupStdName(names, atom, standard_class_names) ||
LookupStdName(names, atom, builtin_property_names);
@@ -1210,6 +1199,9 @@ JS_IdToProtoKey(JSContext* cx, HandleId id)
if (!stdnm)
return JSProto_Null;
if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key))
return JSProto_Null;
MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
return static_cast<JSProtoKey>(stdnm - standard_class_names);
}
@@ -3091,7 +3083,7 @@ DefineSelfHostedProperty(JSContext* cx, HandleObject obj, HandleId id,
return false;
}
MOZ_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>());
setterFunc = &getterValue.toObject().as<JSFunction>();
setterFunc = &setterValue.toObject().as<JSFunction>();
}
JSNative setterOp = JS_DATA_TO_FUNC_PTR(JSNative, setterFunc.get());
@@ -4153,11 +4145,11 @@ JS::FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token)
RootedScript script(maybecx);
{
AutoLastFrameCheck lfc(maybecx);
script = HelperThreadState().finishParseTask(maybecx, rt, token);
script = HelperThreadState().finishScriptParseTask(maybecx, rt, token);
}
return script;
} else {
return HelperThreadState().finishParseTask(maybecx, rt, token);
return HelperThreadState().finishScriptParseTask(maybecx, rt, token);
}
}
+5 -1
View File
@@ -2343,7 +2343,11 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co
* visited. See bug 690622.
*/
ObjectGroup* arrGroup = arr->getGroup(cx);
if (MOZ_UNLIKELY(!arrGroup || arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED)))
if (!arrGroup) {
cx->recoverFromOutOfMemory();
return false;
}
if (MOZ_UNLIKELY(arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED)))
return false;
/*
+3 -2
View File
@@ -670,7 +670,7 @@ JSCompartment::sweepInnerViews()
void
JSCompartment::sweepSavedStacks()
{
savedStacks_.sweep(runtimeFromAnyThread());
savedStacks_.sweep();
}
void
@@ -1078,8 +1078,9 @@ JSCompartment::clearScriptCounts()
// Clear all hasScriptCounts_ flags of JSScript, in order to release all
// ScriptCounts entry of the current compartment.
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
ScriptCounts* value = &r.front().value();
ScriptCounts* value = r.front().value();
r.front().key()->takeOverScriptCountsMapEntry(value);
js_delete(value);
}
js_delete(scriptCountsMap);
+13 -10
View File
@@ -485,7 +485,8 @@ struct JSCompartment
DebuggerNeedsDelazification = 1 << 4
};
unsigned debugModeBits;
unsigned debugModeBits;
friend class AutoRestoreCompartmentDebugMode;
static const unsigned DebuggerObservesMask = IsDebuggee |
DebuggerObservesAllExecution |
@@ -498,17 +499,18 @@ struct JSCompartment
JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options);
~JSCompartment();
bool init(JSContext* maybecx);
MOZ_WARN_UNUSED_RESULT bool init(JSContext* maybecx);
inline bool wrap(JSContext* cx, JS::MutableHandleValue vp,
JS::HandleObject existing = nullptr);
MOZ_WARN_UNUSED_RESULT inline bool wrap(JSContext* cx, JS::MutableHandleValue vp,
JS::HandleObject existing = nullptr);
bool wrap(JSContext* cx, js::MutableHandleString strp);
bool wrap(JSContext* cx, JS::MutableHandleObject obj,
JS::HandleObject existingArg = nullptr);
bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, js::MutableHandleString strp);
MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, JS::MutableHandleObject obj,
JS::HandleObject existingArg = nullptr);
MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
template<typename T> bool wrap(JSContext* cx, JS::AutoVectorRooter<T>& vec) {
template<typename T> MOZ_WARN_UNUSED_RESULT bool wrap(JSContext* cx,
JS::AutoVectorRooter<T>& vec) {
for (size_t i = 0; i < vec.length(); ++i) {
if (!wrap(cx, vec[i]))
return false;
@@ -516,7 +518,8 @@ struct JSCompartment
return true;
};
bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
MOZ_WARN_UNUSED_RESULT bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped,
const js::Value& wrapper);
js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) const {
return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
+1 -1
View File
@@ -3757,7 +3757,7 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassIn
if (is<NativeObject>() && as<NativeObject>().hasDynamicElements()) {
js::ObjectElements* elements = as<NativeObject>().getElementsHeader();
if (!elements->isCopyOnWrite() || elements->ownerObject() == this)
info->objectsMallocHeapElementsNonAsmJS += mallocSizeOf(elements);
info->objectsMallocHeapElementsNormal += mallocSizeOf(elements);
}
// Other things may be measured in the future if DMD indicates it is worthwhile.
+1 -1
View File
@@ -1021,7 +1021,7 @@ JS_vsnprintf(char* out, uint32_t outlen, const char* fmt, va_list ap)
(void) dosprintf(&ss, fmt, ap);
uint32_t charsWritten = ss.cur - ss.base;
MOZ_ASSERT(charsWritten > 0);
MOZ_RELEASE_ASSERT(charsWritten > 0);
// If we didn't append a null then we must have hit the buffer limit. Write
// a null terminator now and return a value indicating that we failed.
+52 -25
View File
@@ -14,6 +14,7 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Vector.h"
#include <algorithm>
@@ -1343,20 +1344,26 @@ JSScript::initScriptCounts(JSContext* cx)
jsbytecode* mainEntry = main();
for (jsbytecode* pc = code(); pc != end; pc = GetNextPc(pc)) {
if (pc == mainEntry) {
if (!jumpTargets.append(pc))
if (!jumpTargets.append(pc)) {
ReportOutOfMemory(cx);
return false;
}
}
bool jump = IsJumpOpcode(JSOp(*pc));
if (jump) {
jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
if (!jumpTargets.append(target))
if (!jumpTargets.append(target)) {
ReportOutOfMemory(cx);
return false;
}
if (BytecodeFallsThrough(JSOp(*pc))) {
jsbytecode* fallthrough = GetNextPc(pc);
if (!jumpTargets.append(fallthrough))
if (!jumpTargets.append(fallthrough)) {
ReportOutOfMemory(cx);
return false;
}
}
}
@@ -1365,8 +1372,10 @@ JSScript::initScriptCounts(JSContext* cx)
int32_t len = GET_JUMP_OFFSET(pc2);
// Default target.
if (!jumpTargets.append(pc + len))
if (!jumpTargets.append(pc + len)) {
ReportOutOfMemory(cx);
return false;
}
pc2 += JUMP_OFFSET_LEN;
int32_t low = GET_JUMP_OFFSET(pc2);
@@ -1378,8 +1387,10 @@ JSScript::initScriptCounts(JSContext* cx)
int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
if (off) {
// Case (i + low)
if (!jumpTargets.append(pc + off))
if (!jumpTargets.append(pc + off)) {
ReportOutOfMemory(cx);
return false;
}
}
}
}
@@ -1396,8 +1407,10 @@ JSScript::initScriptCounts(JSContext* cx)
continue;
jsbytecode* tryTarget = tryStart + tn->length;
if (!jumpTargets.append(tryTarget))
if (!jumpTargets.append(tryTarget)) {
ReportOutOfMemory(cx);
return false;
}
}
}
@@ -1408,8 +1421,10 @@ JSScript::initScriptCounts(JSContext* cx)
// Initialize all PCCounts counters to 0.
ScriptCounts::PCCountsVector base;
if (!base.reserve(jumpTargets.length()))
if (!base.reserve(jumpTargets.length())) {
ReportOutOfMemory(cx);
return false;
}
for (size_t i = 0; i < jumpTargets.length(); i++)
base.infallibleEmplaceBack(pcToOffset(jumpTargets[i]));
@@ -1418,8 +1433,10 @@ JSScript::initScriptCounts(JSContext* cx)
ScriptCountsMap* map = compartment()->scriptCountsMap;
if (!map) {
map = cx->new_<ScriptCountsMap>();
if (!map)
if (!map) {
ReportOutOfMemory(cx);
return false;
}
if (!map->init()) {
js_delete(map);
@@ -1430,12 +1447,25 @@ JSScript::initScriptCounts(JSContext* cx)
compartment()->scriptCountsMap = map;
}
// Register the current ScriptCount in the compartment's map.
if (!map->putNew(this, Move(base)))
// Allocate the ScriptCounts.
ScriptCounts* sc = cx->new_<ScriptCounts>(Move(base));
if (!sc) {
ReportOutOfMemory(cx);
return false;
}
auto guardScriptCounts = mozilla::MakeScopeExit([&] () {
js_delete(sc);
});
// Register the current ScriptCounts in the compartment's map.
if (!map->putNew(this, sc)) {
ReportOutOfMemory(cx);
return false;
}
// safe to set this; we can't fail after this point.
hasScriptCounts_ = true;
guardScriptCounts.release();
// Enable interrupts in any interpreter frames running on this script. This
// is used to let the interpreter increment the PCCounts, if present.
@@ -1460,7 +1490,7 @@ ScriptCounts&
JSScript::getScriptCounts()
{
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
return p->value();
return *p->value();
}
js::PCCounts*
@@ -1620,7 +1650,7 @@ JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue)
{
#ifdef DEBUG
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
MOZ_ASSERT(entryValue == &p->value());
MOZ_ASSERT(entryValue == p->value());
#endif
hasScriptCounts_ = false;
}
@@ -1629,7 +1659,8 @@ void
JSScript::releaseScriptCounts(ScriptCounts* counts)
{
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
*counts = Move(p->value());
*counts = Move(*p->value());
js_delete(p->value());
compartment()->scriptCountsMap->remove(p);
hasScriptCounts_ = false;
}
@@ -3217,21 +3248,17 @@ js::PCToLineNumber(unsigned startLine, jssrcnote* notes, jsbytecode* code, jsbyt
ptrdiff_t target = pc - code;
for (jssrcnote* sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
offset += SN_DELTA(sn);
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
if (type == SRC_SETLINE) {
if (offset <= target)
lineno = unsigned(GetSrcNoteOffset(sn, 0));
column = 0;
} else if (type == SRC_NEWLINE) {
if (offset <= target)
lineno++;
column = 0;
}
if (offset > target)
break;
if (type == SRC_COLSPAN) {
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
if (type == SRC_SETLINE) {
lineno = unsigned(GetSrcNoteOffset(sn, 0));
column = 0;
} else if (type == SRC_NEWLINE) {
lineno++;
column = 0;
} else if (type == SRC_COLSPAN) {
ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
column += colspan;
+8 -9
View File
@@ -520,7 +520,7 @@ class ScriptCounts
// the calls to the JSScript::finalize function which are used to aggregate code
// coverage results on the compartment.
typedef HashMap<JSScript*,
ScriptCounts,
ScriptCounts*,
DefaultHasher<JSScript*>,
SystemAllocPolicy> ScriptCountsMap;
@@ -1052,11 +1052,10 @@ class JSScript : public js::gc::TenuredCell
uint32_t sourceStart_;
uint32_t sourceEnd_;
uint32_t warmUpCount; /* Number of times the script has been called
* or has had backedges taken. When running in
* ion, also increased for any inlined scripts.
* Reset if the script's JIT code is forcibly
* discarded. */
// Number of times the script has been called or has had backedges taken.
// When running in ion, also increased for any inlined scripts. Reset if
// the script's JIT code is forcibly discarded.
mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount;
// 16-bit fields.
@@ -1719,7 +1718,7 @@ class JSScript : public js::gc::TenuredCell
public:
uint32_t getWarmUpCount() const { return warmUpCount; }
uint32_t incWarmUpCounter(uint32_t amount = 1) { return warmUpCount += amount; }
uint32_t* addressOfWarmUpCounter() { return &warmUpCount; }
uint32_t* addressOfWarmUpCounter() { return reinterpret_cast<uint32_t*>(&warmUpCount); }
static size_t offsetOfWarmUpCounter() { return offsetof(JSScript, warmUpCount); }
void resetWarmUpCounter() { incWarmUpResetCounter(); warmUpCount = 0; }
@@ -2143,8 +2142,8 @@ class LazyScript : public gc::TenuredCell
// Function or block chain in which the script is nested, or nullptr.
HeapPtrObject enclosingScope_;
// ScriptSourceObject, or nullptr if the script in which this is nested
// has not been compiled yet. This is never a CCW; we don't clone
// ScriptSourceObject. We leave this set to nullptr until we generate
// bytecode for our immediate parent. This is never a CCW; we don't clone
// LazyScripts into other compartments.
HeapPtrObject sourceObject_;
+2 -3
View File
@@ -37,9 +37,8 @@
*/
#define JS_OLD_GETTER_SETTER_METHODS 1
/* Support for ES6 Classes. */
#ifdef NIGHTLY_BUILD
#define JS_HAS_CLASSES 1
#endif
#endif // NIGHTLY_BUILD
#endif /* jsversion_h */
+114 -2
View File
@@ -3332,7 +3332,6 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp)
return false;
}
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
JSFlatString* scriptContents = args[0].toString()->ensureFlat(cx);
if (!scriptContents)
return false;
@@ -3364,7 +3363,7 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp)
SourceBufferHolder srcBuf(chars, scriptContents->length(),
SourceBufferHolder::NoOwnership);
RootedObject module(cx, frontend::CompileModule(cx, global, options, srcBuf));
RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf));
if (!module)
return false;
@@ -3698,6 +3697,109 @@ runOffThreadScript(JSContext* cx, unsigned argc, Value* vp)
return JS_ExecuteScript(cx, script, args.rval());
}
static bool
CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
{
MOZ_ASSERT(JS::CanCompileOffThread(cx, options, length));
return StartOffThreadParseModule(cx, options, chars, length, callback, callbackData);
}
static JSObject*
FinishOffThreadModule(JSContext* maybecx, JSRuntime* rt, void* token)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
return HelperThreadState().finishModuleParseTask(maybecx, rt, token);
}
static bool
OffThreadCompileModule(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1 || !args[0].isString()) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
"offThreadCompileModule");
return false;
}
JSAutoByteString fileNameBytes;
CompileOptions options(cx);
options.setIntroductionType("js shell offThreadCompileModule")
.setFileAndLine("<string>", 1);
options.setIsRunOnce(true)
.setSourceIsLazy(false);
options.forceAsync = true;
JSString* scriptContents = args[0].toString();
AutoStableStringChars stableChars(cx);
if (!stableChars.initTwoByte(cx, scriptContents))
return false;
size_t length = scriptContents->length();
const char16_t* chars = stableChars.twoByteRange().start().get();
// Make sure we own the string's chars, so that they are not freed before
// the compilation is finished.
ScopedJSFreePtr<char16_t> ownedChars;
if (stableChars.maybeGiveOwnershipToCaller()) {
ownedChars = const_cast<char16_t*>(chars);
} else {
char16_t* copy = cx->pod_malloc<char16_t>(length);
if (!copy)
return false;
mozilla::PodCopy(copy, chars, length);
ownedChars = copy;
chars = copy;
}
if (!JS::CanCompileOffThread(cx, options, length)) {
JS_ReportError(cx, "cannot compile code on worker thread");
return false;
}
if (!offThreadState.startIfIdle(cx, ownedChars)) {
JS_ReportError(cx, "called offThreadCompileModule without receiving prior off-thread "
"compilation");
return false;
}
if (!CompileOffThreadModule(cx, options, chars, length,
OffThreadCompileScriptCallback, nullptr))
{
offThreadState.abandon(cx);
return false;
}
args.rval().setUndefined();
return true;
}
static bool
FinishOffThreadModule(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSRuntime* rt = cx->runtime();
if (OffThreadParsingMustWaitForGC(rt))
gc::AutoFinishGC finishgc(rt);
void* token = offThreadState.waitUntilDone(cx);
if (!token) {
JS_ReportError(cx, "called finishOffThreadModule when no compilation is pending");
return false;
}
RootedObject module(cx, FinishOffThreadModule(cx, rt, token));
if (!module)
return false;
args.rval().setObject(*module);
return true;
}
struct MOZ_RAII FreeOnReturn
{
JSContext* cx;
@@ -5057,6 +5159,16 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
" throw the appropriate exception; otherwise, run the script and return\n"
" its value."),
JS_FN_HELP("offThreadCompileModule", OffThreadCompileModule, 1, 0,
"offThreadCompileModule(code)",
" Compile |code| on a helper thread. To wait for the compilation to finish\n"
" and get the module object, call |finishOffThreadModule|."),
JS_FN_HELP("finishOffThreadModule", FinishOffThreadModule, 0, 0,
"finishOffThreadModule()",
" Wait for off-thread compilation to complete. If an error occurred,\n"
" throw the appropriate exception; otherwise, return the module object"),
JS_FN_HELP("timeout", Timeout, 1, 0,
"timeout([seconds], [func])",
" Get/Set the limit in seconds for the execution time for the current context.\n"
@@ -7,7 +7,7 @@ function TestArrayIteratorPrototypeConfusion() {
throw new Error("Call did not throw");
} catch (e) {
assertEq(e instanceof TypeError, true);
assertEq(e.message, "CallArrayIteratorMethodIfWrapped method called on incompatible Array Iterator");
assertEq(e.message, "next method called on incompatible Array Iterator");
}
}
TestArrayIteratorPrototypeConfusion();
+72
View File
@@ -0,0 +1,72 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// We should preserve holes when sorting sparce arrays.
// See bug: 1246860
function denseCount(arr) {
var c = 0;
for (var i = 0; i < arr.length; i++)
if (i in arr)
c++;
return c;
}
let a = [,,,,,,,,,,,,,,,,,,,,{size: 1},{size: 2}];
let b = [,,,,,,,,,,,,,,,,,,,,{size: 1},{size: 2}].sort();
let c = [,,,,,,,,,,,,,,,,,,,,{size: 1},{size: 2}].sort((a, b) => {+a.size - +b.size});
assertEq(a.length, 22);
assertEq(denseCount(a), 2);
assertEq(a.length, b.length);
assertEq(b.length, c.length);
assertEq(denseCount(a), denseCount(b));
assertEq(denseCount(b), denseCount(c));
let superSparce = new Array(5000);
superSparce[0] = 99;
superSparce[4000] = 0;
superSparce[4999] = -1;
assertEq(superSparce.length, 5000);
assertEq(denseCount(superSparce), 3);
superSparce.sort((a, b) => 1*a-b);
assertEq(superSparce.length, 5000);
assertEq(denseCount(superSparce), 3);
assertEq(superSparce[0], -1);
assertEq(superSparce[1], 0);
assertEq(superSparce[2], 99);
let allHoles = new Array(2600);
assertEq(allHoles.length, 2600);
assertEq(denseCount(allHoles), 0);
allHoles.sort((a, b) => 1*a-b);
assertEq(allHoles.length, 2600);
assertEq(denseCount(allHoles), 0);
let oneHole = new Array(2600);
oneHole[1399] = {size: 27};
assertEq(oneHole.length, 2600);
assertEq(denseCount(oneHole), 1);
oneHole.sort((a, b) => {+a.size - +b.size});
assertDeepEq(oneHole[0], {size: 27});
assertEq(oneHole.length, 2600);
assertEq(denseCount(oneHole), 1);
// Ensure that the array setter is touch touched during sorting.
Object.defineProperty(Array.prototype, "0", {
set: (value) => {throw "Illegally touched the array's setter!"},
configurable: true
});
assertThrows(() => {o[1] = 11;});
let o = [,,,,,,,,,,,,,,,,,,,,{size: 1},{size: 2}];
o.sort((a, b) => {+a.size - +b.size});
delete Array.prototype["0"];
if (typeof reportCompare === 'function')
reportCompare(0, 0);
@@ -0,0 +1,167 @@
var BUGNUMBER = 992617;
var summary = "Implement arguments[@@iterator].";
print(BUGNUMBER + ": " + summary);
// MappedArgumentsObject
let mapped = [
function(a, b, c) {
assertEq(Symbol.iterator in arguments, true);
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function(a, b, c) {
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function(a, b, c) {
arguments[Symbol.iterator] = 10;
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function(a, b, c) {
Object.defineProperty(arguments, Symbol.iterator, {
value: 10, writable: true, enumerable: true, configurable: true
});
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function(a, b, c) {
assertEq(arguments[Symbol.iterator], Array.prototype[Symbol.iterator]);
},
function(a, b, c) {
assertEq(arguments[Symbol.iterator].name, "values");
},
function(a, b, c) {
var desc = Object.getOwnPropertyDescriptor(arguments, Symbol.iterator);
assertEq("value" in desc, true);
assertEq(desc.value, Array.prototype[Symbol.iterator]);
assertEq(desc.writable, true);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
},
function(a, b, c) {
var iter = arguments[Symbol.iterator]();
assertDeepEq(iter.next(), { value: 10, done: false });
assertDeepEq(iter.next(), { value: 20, done: false });
assertDeepEq(iter.next(), { value: 30, done: false });
assertDeepEq(iter.next(), { value: undefined, done: true });
},
function(a, b, c) {
assertDeepEq([...arguments], [10, 20, 30]);
},
function(a, b, c) {
b = 40;
assertDeepEq([...arguments], [10, 40, 30]);
},
function(a, b, c) {
arguments.length = 4;
assertDeepEq([...arguments], [10, 20, 30, undefined]);
},
function(a, b, c) {
arguments[5] = 50;
assertDeepEq([...arguments], [10, 20, 30]);
},
function(a, b, c) {
arguments[Symbol.iterator] = function*() {
yield 40;
yield 50;
yield 60;
};
assertDeepEq([...arguments], [40, 50, 60]);
},
];
for (let f of mapped) {
f(10, 20, 30);
}
var g1 = newGlobal();
assertEq(g1.eval(`
function f(a, b, c) {
return arguments[Symbol.iterator].name;
}
f(1, 2, 3);
`), "values");
// UnmappedArgumentsObject
let unmapped = [
function([a], b, c) {
assertEq(Symbol.iterator in arguments, true);
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function([a], b, c) {
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function([a], b, c) {
arguments[Symbol.iterator] = 10;
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function([a], b, c) {
Object.defineProperty(arguments, Symbol.iterator, {
value: 10, writable: true, enumerable: true, configurable: true
});
delete arguments[Symbol.iterator];
assertEq(Symbol.iterator in arguments, false);
},
function([a], b, c) {
assertEq(arguments[Symbol.iterator], Array.prototype[Symbol.iterator]);
},
function([a], b, c) {
assertEq(arguments[Symbol.iterator].name, "values");
},
function([a], b, c) {
var desc = Object.getOwnPropertyDescriptor(arguments, Symbol.iterator);
assertEq("value" in desc, true);
assertEq(desc.value, Array.prototype[Symbol.iterator]);
assertEq(desc.writable, true);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
},
function([a], b, c) {
var iter = arguments[Symbol.iterator]();
assertDeepEq(iter.next(), { value: [10], done: false });
assertDeepEq(iter.next(), { value: 20, done: false });
assertDeepEq(iter.next(), { value: 30, done: false });
assertDeepEq(iter.next(), { value: undefined, done: true });
},
function([a], b, c) {
assertDeepEq([...arguments], [[10], 20, 30]);
},
function([a], b, c) {
b = 40;
assertDeepEq([...arguments], [[10], 20, 30]);
},
function([a], b, c) {
arguments.length = 4;
assertDeepEq([...arguments], [[10], 20, 30, undefined]);
},
function([a], b, c) {
arguments[5] = 50;
assertDeepEq([...arguments], [[10], 20, 30]);
},
function([a], b, c) {
arguments[Symbol.iterator] = function*() {
yield 40;
yield 50;
yield 60;
};
assertDeepEq([...arguments], [40, 50, 60]);
},
];
for (let f of unmapped) {
f([10], 20, 30);
}
var g2 = newGlobal();
assertEq(g2.eval(`
function f([a], b, c) {
return arguments[Symbol.iterator].name;
}
f([1], 2, 3);
`), "values");
if (typeof reportCompare === "function")
reportCompare(true, true);
@@ -7,7 +7,7 @@ function TestStringIteratorPrototypeConfusion() {
throw new Error("Call did not throw");
} catch (e) {
assertEq(e instanceof TypeError, true);
assertEq(e.message, "CallStringIteratorMethodIfWrapped method called on incompatible String Iterator");
assertEq(e.message, "next method called on incompatible String Iterator");
}
}
TestStringIteratorPrototypeConfusion();
+43
View File
@@ -328,6 +328,8 @@ ArgumentsObject::obj_delProperty(JSContext* cx, HandleObject obj, HandleId id,
argsobj.markLengthOverridden();
} else if (JSID_IS_ATOM(id, cx->names().callee)) {
argsobj.as<MappedArgumentsObject>().clearCallee();
} else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
argsobj.markIteratorOverridden();
}
return result.succeed();
}
@@ -398,11 +400,34 @@ MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
NativeDefineProperty(cx, argsobj, id, vp, nullptr, nullptr, attrs, result);
}
static bool
DefineArgumentsIterator(JSContext* cx, Handle<ArgumentsObject*> argsobj)
{
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
HandlePropertyName shName = cx->names().ArrayValues;
RootedAtom name(cx, cx->names().values);
RootedValue val(cx);
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 0, &val))
return false;
return NativeDefineProperty(cx, argsobj, iteratorId, val, nullptr, nullptr, JSPROP_RESOLVING);
}
/* static */ bool
MappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
{
Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>());
if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
if (argsobj->hasOverriddenIterator())
return true;
if (!DefineArgumentsIterator(cx, argsobj))
return false;
*resolvedp = true;
return true;
}
unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE | JSPROP_RESOLVING;
if (JSID_IS_INT(id)) {
uint32_t arg = uint32_t(JSID_TO_INT(id));
@@ -448,6 +473,10 @@ MappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
if (!HasProperty(cx, argsobj, id, &found))
return false;
id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
if (!HasProperty(cx, argsobj, id, &found))
return false;
for (unsigned i = 0; i < argsobj->initialLength(); i++) {
id = INT_TO_JSID(i);
if (!HasProperty(cx, argsobj, id, &found))
@@ -519,6 +548,16 @@ UnmappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId i
{
Rooted<UnmappedArgumentsObject*> argsobj(cx, &obj->as<UnmappedArgumentsObject>());
if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
if (argsobj->hasOverriddenIterator())
return true;
if (!DefineArgumentsIterator(cx, argsobj))
return false;
*resolvedp = true;
return true;
}
unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
GetterOp getter = UnmappedArgGetter;
SetterOp setter = UnmappedArgSetter;
@@ -570,6 +609,10 @@ UnmappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
if (!HasProperty(cx, argsobj, id, &found))
return false;
id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
if (!HasProperty(cx, argsobj, id, &found))
return false;
for (unsigned i = 0; i < argsobj->initialLength(); i++) {
id = INT_TO_JSID(i);
if (!HasProperty(cx, argsobj, id, &found))
+17 -3
View File
@@ -109,8 +109,9 @@ static const unsigned ARGS_LENGTH_MAX = 500 * 1000;
*
* INITIAL_LENGTH_SLOT
* Stores the initial value of arguments.length, plus a bit indicating
* whether arguments.length has been modified. Use initialLength() and
* hasOverriddenLength() to access these values. If arguments.length has
* whether arguments.length and/or arguments[@@iterator] have been
* modified. Use initialLength(), hasOverriddenLength(), and
* hasOverriddenIterator() to access these values. If arguments.length has
* been modified, then the current value of arguments.length is stored in
* another slot associated with a new property.
* DATA_SLOT
@@ -125,7 +126,8 @@ class ArgumentsObject : public NativeObject
public:
static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
static const uint32_t PACKED_BITS_COUNT = 1;
static const uint32_t ITERATOR_OVERRIDDEN_BIT = 0x2;
static const uint32_t PACKED_BITS_COUNT = 2;
protected:
template <typename CopyArgs>
@@ -185,6 +187,18 @@ class ArgumentsObject : public NativeObject
setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
}
/* True iff arguments[@@iterator] has been assigned or its attributes
* changed. */
bool hasOverriddenIterator() const {
const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT);
return v.toInt32() & ITERATOR_OVERRIDDEN_BIT;
}
void markIteratorOverridden() {
uint32_t v = getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | ITERATOR_OVERRIDDEN_BIT;
setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
}
/*
* Because the arguments object is a real object, its elements may be
* deleted. This is implemented by setting a 'deleted' flag for the arg
+7 -6
View File
@@ -576,16 +576,17 @@ ArrayBufferObject::setDataPointer(BufferContents contents, OwnsState ownsData)
setFlags((flags() & ~KIND_MASK) | contents.kind());
}
size_t
uint32_t
ArrayBufferObject::byteLength() const
{
return size_t(getSlot(BYTE_LENGTH_SLOT).toDouble());
return getSlot(BYTE_LENGTH_SLOT).toInt32();
}
void
ArrayBufferObject::setByteLength(size_t length)
ArrayBufferObject::setByteLength(uint32_t length)
{
setSlot(BYTE_LENGTH_SLOT, DoubleValue(length));
MOZ_ASSERT(length <= INT32_MAX);
setSlot(BYTE_LENGTH_SLOT, Int32Value(length));
}
uint32_t
@@ -755,10 +756,10 @@ ArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf m
switch (buffer.bufferKind()) {
case PLAIN:
info->objectsMallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
info->objectsMallocHeapElementsNormal += mallocSizeOf(buffer.dataPointer());
break;
case MAPPED:
info->objectsNonHeapElementsMapped += buffer.byteLength();
info->objectsNonHeapElementsNormal += buffer.byteLength();
break;
case WASM_MALLOCED:
info->objectsMallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
+2 -2
View File
@@ -288,7 +288,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
public:
uint8_t* dataPointer() const;
SharedMem<uint8_t*> dataPointerShared() const;
size_t byteLength() const;
uint32_t byteLength() const;
BufferContents contents() const {
return BufferContents(dataPointer(), bufferKind());
}
@@ -339,7 +339,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
protected:
void setDataPointer(BufferContents contents, OwnsState ownsState);
void setByteLength(size_t length);
void setByteLength(uint32_t length);
uint32_t flags() const;
void setFlags(uint32_t flags);
+4
View File
@@ -11,6 +11,7 @@
#include "proxy/Proxy.h"
#include "vm/ProxyObject.h"
#include "vm/SelfHosting.h"
using namespace js;
@@ -27,6 +28,9 @@ JS::detail::CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl
return Proxy::nativeCall(cx, test, impl, args);
}
if (IsCallSelfHostedNonGenericMethod(impl))
return ReportIncompatibleSelfHostedMethod(cx, args);
ReportIncompatible(cx, args);
return false;
}
+4 -6
View File
@@ -296,17 +296,15 @@
macro(iterator, iterator, "iterator") \
macro(match, match, "match") \
macro(species, species, "species") \
macro(hasInstance, hasInstance, "hasInstance") \
macro(toPrimitive, toPrimitive, "toPrimitive") \
macro(unscopables, unscopables, "unscopables") \
/* Same goes for the descriptions of the well-known symbols. */ \
macro(Symbol_create, Symbol_create, "Symbol.create") \
macro(Symbol_isConcatSpreadable, Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") \
macro(Symbol_isRegExp, Symbol_isRegExp, "Symbol.isRegExp") \
macro(Symbol_iterator, Symbol_iterator, "Symbol.iterator") \
macro(Symbol_match, Symbol_match, "Symbol.match") \
macro(Symbol_species, Symbol_species, "Symbol.species") \
macro(Symbol_hasInstance, Symbol_hasInstance, "Symbol.hasInstance") \
macro(Symbol_isConcatSpreadable, Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") \
macro(Symbol_iterator, Symbol_iterator, "Symbol.iterator") \
macro(Symbol_match, Symbol_match, "Symbol.match") \
macro(Symbol_species, Symbol_species, "Symbol.species") \
macro(Symbol_toPrimitive, Symbol_toPrimitive, "Symbol.toPrimitive") \
macro(Symbol_unscopables, Symbol_unscopables, "Symbol.unscopables") \
/* Function names for properties named by symbols. */ \
+134 -35
View File
@@ -20,6 +20,7 @@
#include "jswrapper.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/Parser.h"
#include "gc/Marking.h"
#include "jit/BaselineDebugModeOSR.h"
#include "jit/BaselineJIT.h"
@@ -248,6 +249,28 @@ class Debugger::FrameRange
}
};
class AutoRestoreCompartmentDebugMode
{
JSCompartment* comp_;
unsigned bits_;
public:
explicit AutoRestoreCompartmentDebugMode(JSCompartment* comp)
: comp_(comp), bits_(comp->debugModeBits)
{
MOZ_ASSERT(comp_);
}
~AutoRestoreCompartmentDebugMode() {
if (comp_)
comp_->debugModeBits = bits_;
}
void release() {
comp_ = nullptr;
}
};
// Given a Debugger instance dbg, if it is enabled, prevents all its debuggee
// compartments from executing scripts. Attempts to run script will throw an
// instance of Debugger.DebuggeeWouldRun from the topmost locked Debugger's
@@ -2295,27 +2318,6 @@ UpdateExecutionObservabilityOfScriptsInZone(JSContext* cx, Zone* zone,
JSRuntime* rt = cx->runtime();
FreeOp* fop = cx->runtime()->defaultFreeOp();
// Mark active baseline scripts in the observable set so that they don't
// get discarded. They will be recompiled.
for (JitActivationIterator actIter(rt); !actIter.done(); ++actIter) {
if (actIter->compartment()->zone() != zone)
continue;
for (JitFrameIterator iter(actIter); !iter.done(); ++iter) {
switch (iter.type()) {
case JitFrame_BaselineJS:
MarkBaselineScriptActiveIfObservable(iter.script(), obs);
break;
case JitFrame_IonJS:
MarkBaselineScriptActiveIfObservable(iter.script(), obs);
for (InlineFrameIterator inlineIter(rt, &iter); inlineIter.more(); ++inlineIter)
MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
break;
default:;
}
}
}
Vector<JSScript*> scripts(cx);
// Iterate through observable scripts, invalidating their Ion scripts and
@@ -2340,6 +2342,30 @@ UpdateExecutionObservabilityOfScriptsInZone(JSContext* cx, Zone* zone,
}
}
// Code below this point must be infallible to ensure the active bit of
// BaselineScripts is in a consistent state.
//
// Mark active baseline scripts in the observable set so that they don't
// get discarded. They will be recompiled.
for (JitActivationIterator actIter(rt); !actIter.done(); ++actIter) {
if (actIter->compartment()->zone() != zone)
continue;
for (JitFrameIterator iter(actIter); !iter.done(); ++iter) {
switch (iter.type()) {
case JitFrame_BaselineJS:
MarkBaselineScriptActiveIfObservable(iter.script(), obs);
break;
case JitFrame_IonJS:
MarkBaselineScriptActiveIfObservable(iter.script(), obs);
for (InlineFrameIterator inlineIter(rt, &iter); inlineIter.more(); ++inlineIter)
MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
break;
default:;
}
}
}
// Iterate through the scripts again and finish discarding
// BaselineScripts. This must be done as a separate phase as we can only
// discard the BaselineScript on scripts that have no IonScript.
@@ -2475,11 +2501,16 @@ Debugger::updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving obser
// so add the compartment to the set only if we are observing.
if (observing && !obs.add(comp))
return false;
comp->updateDebuggerObservesAllExecution();
}
return updateExecutionObservability(cx, obs, observing);
if (!updateExecutionObservability(cx, obs, observing))
return false;
typedef ExecutionObservableCompartments::CompartmentRange CompartmentRange;
for (CompartmentRange r = obs.compartments()->all(); !r.empty(); r.popFront())
r.front()->updateDebuggerObservesAllExecution();
return true;
}
bool
@@ -3039,10 +3070,14 @@ Debugger::setHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which)
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE_OR_UNDEFINED);
return false;
}
dbg.object->setReservedSlot(JSSLOT_DEBUG_HOOK_START + which, args[0]);
uint32_t slot = JSSLOT_DEBUG_HOOK_START + which;
RootedValue oldHook(cx, dbg.object->getReservedSlot(slot));
dbg.object->setReservedSlot(slot, args[0]);
if (hookObservesAllExecution(which)) {
if (!dbg.updateObservesAllExecutionOnDebuggees(cx, dbg.observesAllExecution()))
if (!dbg.updateObservesAllExecutionOnDebuggees(cx, dbg.observesAllExecution())) {
dbg.object->setReservedSlot(slot, oldHook);
return false;
}
}
args.rval().setUndefined();
return true;
@@ -3677,6 +3712,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
});
// (6)
AutoRestoreCompartmentDebugMode debugModeGuard(debuggeeCompartment);
debuggeeCompartment->setIsDebuggee();
debuggeeCompartment->updateDebuggerObservesAsmJS();
debuggeeCompartment->updateDebuggerObservesCoverage();
@@ -3688,6 +3724,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
zoneDebuggersGuard.release();
debuggeeZonesGuard.release();
allocationsTrackingGuard.release();
debugModeGuard.release();
return true;
}
@@ -4690,6 +4727,56 @@ Debugger::endTraceLogger(JSContext* cx, unsigned argc, Value* vp)
return true;
}
bool
Debugger::isCompilableUnit(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, "Debugger.isCompilableUnit", 1))
return false;
if (!args[0].isString()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_NOT_EXPECTED_TYPE, "Debugger.isCompilableUnit",
"string", InformalValueTypeName(args[0]));
return false;
}
JSString* str = args[0].toString();
size_t length = GetStringLength(str);
AutoStableStringChars chars(cx);
if (!chars.initTwoByte(cx, str))
return false;
bool result = true;
CompileOptions options(cx);
frontend::Parser<frontend::FullParseHandler> parser(cx, &cx->tempLifoAlloc(),
options, chars.twoByteChars(),
length, /* foldConstants = */ true,
nullptr, nullptr);
JSErrorReporter older = JS_SetErrorReporter(cx->runtime(), nullptr);
if (!parser.checkOptions() || !parser.parse()) {
// We ran into an error. If it was because we ran out of memory we report
// it in the usual way.
if (cx->isThrowingOutOfMemory()) {
JS_SetErrorReporter(cx->runtime(), older);
return false;
}
// If it was because we ran out of source, we return false so our caller
// knows to try to collect more [source].
if (parser.isUnexpectedEOF())
result = false;
cx->clearPendingException();
}
JS_SetErrorReporter(cx->runtime(), older);
args.rval().setBoolean(result);
return true;
}
bool
Debugger::drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp)
{
@@ -4811,7 +4898,11 @@ const JSFunctionSpec Debugger::methods[] = {
JS_FS_END
};
const JSFunctionSpec Debugger::static_methods[] {
JS_FN("isCompilableUnit", Debugger::isCompilableUnit, 1, 0),
JS_FS_END
};
/*** Debugger.Script *****************************************************************************/
static inline JSScript*
@@ -5581,6 +5672,19 @@ Debugger::observesScript(JSScript* script) const
Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to,
ScriptFrameIter& iter)
{
auto removeFromDebuggerFramesOnExit = MakeScopeExit([&] {
// Remove any remaining old entries on exit, as the 'from' frame will
// be gone. On success, the range will be empty.
for (Debugger::FrameRange r(from); !r.empty(); r.popFront()) {
r.frontFrame()->setPrivate(nullptr);
r.removeFrontFrame();
}
// Rekey missingScopes to maintain Debugger.Environment identity and
// forward liveScopes to point to the new frame.
DebugScopes::forwardLiveFrame(cx, from, to);
});
// Forward live Debugger.Frame objects.
for (Debugger::FrameRange r(from); !r.empty(); r.popFront()) {
RootedNativeObject frameobj(cx, r.frontFrame());
@@ -5594,7 +5698,7 @@ Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, AbstractFramePt
return false;
frameobj->setPrivate(data);
// Remove the old entry before mutating the HashMap.
// Remove the old frame.
r.removeFrontFrame();
// Add the frame object with |to| as key.
@@ -5604,11 +5708,6 @@ Debugger::replaceFrameGuts(JSContext* cx, AbstractFramePtr from, AbstractFramePt
}
}
// Rekey missingScopes to maintain Debugger.Environment identity and
// forward liveScopes to point to the new frame, as the old frame will be
// gone.
DebugScopes::forwardLiveFrame(cx, from, to);
return true;
}
@@ -8589,8 +8688,8 @@ JS_DefineDebuggerObject(JSContext* cx, HandleObject obj)
return false;
debugProto = InitClass(cx, obj,
objProto, &Debugger::jsclass, Debugger::construct,
1, Debugger::properties, Debugger::methods, nullptr, nullptr,
debugCtor.address());
1, Debugger::properties, Debugger::methods, nullptr,
Debugger::static_methods, debugCtor.address());
if (!debugProto)
return false;
+2
View File
@@ -585,6 +585,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
static bool drainTraceLoggerScriptCalls(JSContext* cx, unsigned argc, Value* vp);
static bool startTraceLogger(JSContext* cx, unsigned argc, Value* vp);
static bool endTraceLogger(JSContext* cx, unsigned argc, Value* vp);
static bool isCompilableUnit(JSContext* cx, unsigned argc, Value* vp);
#ifdef NIGHTLY_BUILD
static bool setupTraceLogger(JSContext* cx, unsigned argc, Value* vp);
static bool drainTraceLogger(JSContext* cx, unsigned argc, Value* vp);
@@ -592,6 +593,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
static bool construct(JSContext* cx, unsigned argc, Value* vp);
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static const JSFunctionSpec static_methods[];
static void removeFromFrameMapsAndClearBreakpointsIn(JSContext* cx, AbstractFramePtr frame);
static bool updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObservableSet& obs,
+39 -3
View File
@@ -90,8 +90,22 @@ js::GlobalObject::getTypedObjectModule() const {
return v.toObject().as<TypedObjectModuleObject>();
}
/* static */ bool
GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key)
{
#ifdef ENABLE_SHARED_ARRAY_BUFFER
// Return true if the given constructor has been disabled at run-time.
switch (key) {
case JSProto_Atomics:
case JSProto_SharedArrayBuffer:
return !cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled();
default:
return false;
}
#else
return false;
#endif
}
/* static */ bool
GlobalObject::ensureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
@@ -118,6 +132,9 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
if (!init && !clasp)
return true; // JSProto_Null or a compile-time-disabled feature.
if (skipDeselectedConstructor(cx, key))
return true;
// Some classes have no init routine, which means that they're disabled at
// compile-time. We could try to enforce that callers never pass such keys
// to resolveConstructor, but that would cramp the style of consumers like
@@ -417,6 +434,7 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
InitBareWeakMapCtor(cx, global) &&
InitStopIterationClass(cx, global) &&
InitSelfHostingCollectionIteratorFunctions(cx, global) &&
@@ -661,7 +679,10 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal)
{
if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal)) {
bool exists = false;
if (!GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal, &exists))
return false;
if (exists) {
RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
if (fun->atom() == name)
return true;
@@ -725,3 +746,18 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
holder->setSlot(shape->slot(), value);
return true;
}
/* static */ bool
GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global)
{
if (global->getSlot(MODULE_PROTO).isUndefined()) {
MOZ_ASSERT(global->getSlot(IMPORT_ENTRY_PROTO).isUndefined() &&
global->getSlot(EXPORT_ENTRY_PROTO).isUndefined());
if (!js::InitModuleClasses(cx, global))
return false;
}
MOZ_ASSERT(global->getSlot(MODULE_PROTO).isObject() &&
global->getSlot(IMPORT_ENTRY_PROTO).isObject() &&
global->getSlot(EXPORT_ENTRY_PROTO).isObject());
return true;
}
+37 -7
View File
@@ -164,6 +164,7 @@ class GlobalObject : public NativeObject
MOZ_ASSERT(key <= JSProto_LIMIT);
return getSlot(APPLICATION_SLOTS + key);
}
static bool skipDeselectedConstructor(JSContext* cx, JSProtoKey key);
static bool ensureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key);
static bool resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key);
static bool initBuiltinConstructor(JSContext* cx, Handle<GlobalObject*> global,
@@ -467,16 +468,39 @@ class GlobalObject : public NativeObject
return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto);
}
static bool ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global);
JSObject* maybeGetModulePrototype() {
Value value = getSlot(MODULE_PROTO);
return value.isUndefined() ? nullptr : &value.toObject();
}
JSObject* maybeGetImportEntryPrototype() {
Value value = getSlot(IMPORT_ENTRY_PROTO);
return value.isUndefined() ? nullptr : &value.toObject();
}
JSObject* maybeGetExportEntryPrototype() {
Value value = getSlot(EXPORT_ENTRY_PROTO);
return value.isUndefined() ? nullptr : &value.toObject();
}
JSObject* getModulePrototype() {
return &getSlot(MODULE_PROTO).toObject();
JSObject* proto = maybeGetModulePrototype();
MOZ_ASSERT(proto);
return proto;
}
JSObject* getImportEntryPrototype() {
return &getSlot(IMPORT_ENTRY_PROTO).toObject();
JSObject* proto = maybeGetImportEntryPrototype();
MOZ_ASSERT(proto);
return proto;
}
JSObject* getExportEntryPrototype() {
return &getSlot(EXPORT_ENTRY_PROTO).toObject();
JSObject* proto = maybeGetExportEntryPrototype();
MOZ_ASSERT(proto);
return proto;
}
static JSFunction*
@@ -600,7 +624,7 @@ class GlobalObject : public NativeObject
static bool
maybeGetIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, Handle<PropertyName*> name,
MutableHandleValue vp)
MutableHandleValue vp, bool* exists)
{
NativeObject* holder = getIntrinsicsHolder(cx, global);
if (!holder)
@@ -608,15 +632,21 @@ class GlobalObject : public NativeObject
if (Shape* shape = holder->lookupPure(name)) {
vp.set(holder->getSlot(shape->slot()));
return true;
*exists = true;
} else {
*exists = false;
}
return false;
return true;
}
static bool getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName name, MutableHandleValue value)
{
if (GlobalObject::maybeGetIntrinsicValue(cx, global, name, value))
bool exists = false;
if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists))
return false;
if (exists)
return true;
if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
return false;
+189 -68
View File
@@ -195,10 +195,10 @@ static const JSClass parseTaskGlobalClass = {
JS_GlobalObjectTraceHook
};
ParseTask::ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, JSContext* initCx,
const char16_t* chars, size_t length,
ParseTask::ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
: cx(cx), options(initCx), chars(chars), length(length),
: kind(kind), cx(cx), options(initCx), chars(chars), length(length),
alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
exclusiveContextGlobal(initCx->runtime(), exclusiveContextGlobal),
callback(callback), callbackData(callbackData),
@@ -244,6 +244,52 @@ ParseTask::~ParseTask()
js_delete(errors[i]);
}
ScriptParseTask::ScriptParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
: ParseTask(ParseTaskKind::Script, cx, exclusiveContextGlobal, initCx, chars, length, callback,
callbackData)
{
}
void
ScriptParseTask::parse()
{
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
// ! WARNING WARNING WARNING !
//
// See comment in Parser::bindLexical about optimizing global lexical
// bindings. If we start optimizing them, passing in task->cx's
// global lexical scope would be incorrect!
//
// ! WARNING WARNING WARNING !
Rooted<ClonedBlockObject*> globalLexical(cx, &cx->global()->lexicalScope());
Rooted<StaticScope*> staticScope(cx, &globalLexical->staticBlock());
script = frontend::CompileScript(cx, &alloc, globalLexical, staticScope, nullptr,
options, srcBuf,
/* source_ = */ nullptr,
/* extraSct = */ nullptr,
/* sourceObjectOut = */ sourceObject.address());
}
ModuleParseTask::ModuleParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
: ParseTask(ParseTaskKind::Module, cx, exclusiveContextGlobal, initCx, chars, length, callback,
callbackData)
{
}
void
ModuleParseTask::parse()
{
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
ModuleObject* module = frontend::CompileModule(cx, options, srcBuf, &alloc);
if (module)
script = module->script();
}
void
js::CancelOffThreadParses(JSRuntime* rt)
{
@@ -285,7 +331,8 @@ js::CancelOffThreadParses(JSRuntime* rt)
if (task->runtimeMatches(rt)) {
found = true;
AutoUnlockHelperThreadState unlock;
HelperThreadState().finishParseTask(/* maybecx = */ nullptr, rt, task);
HelperThreadState().finishParseTask(/* maybecx = */ nullptr, rt, task->kind,
task);
}
}
if (!found)
@@ -319,7 +366,7 @@ EnsureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
// Initialize all classes potentially created during parsing for use in parser
// data structures, template objects, &c.
static bool
EnsureParserCreatedClasses(JSContext* cx)
EnsureParserCreatedClasses(JSContext* cx, ParseTaskKind kind)
{
Handle<GlobalObject*> global = cx->global();
@@ -338,18 +385,15 @@ EnsureParserCreatedClasses(JSContext* cx)
if (!GlobalObject::initStarGenerators(cx, global))
return false; // needed by function*() {} and generator comprehensions
if (kind == ParseTaskKind::Module && !GlobalObject::ensureModulePrototypesCreated(cx, global))
return false;
return true;
}
bool
js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
static JSObject*
CreateGlobalForOffThreadParse(JSContext* cx, ParseTaskKind kind, const gc::AutoSuppressGC& nogc)
{
// Suppress GC so that calls below do not trigger a new incremental GC
// which could require barriers on the atoms compartment.
gc::AutoSuppressGC suppress(cx);
JSCompartment* currentCompartment = cx->compartment();
JS::CompartmentOptions compartmentOptions(currentCompartment->creationOptions(),
@@ -367,21 +411,60 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio
JSObject* global = JS_NewGlobalObject(cx, &parseTaskGlobalClass, nullptr,
JS::FireOnNewGlobalHook, compartmentOptions);
if (!global)
return false;
return nullptr;
JS_SetCompartmentPrincipals(global->compartment(), currentCompartment->principals());
// Initialize all classes required for parsing while still on the main
// thread, for both the target and the new global so that prototype
// pointers can be changed infallibly after parsing finishes.
if (!EnsureParserCreatedClasses(cx))
return false;
if (!EnsureParserCreatedClasses(cx, kind))
return nullptr;
{
AutoCompartment ac(cx, global);
if (!EnsureParserCreatedClasses(cx))
return false;
if (!EnsureParserCreatedClasses(cx, kind))
return nullptr;
}
return global;
}
static bool
QueueOffThreadParseTask(JSContext* cx, ParseTask* task)
{
if (OffThreadParsingMustWaitForGC(cx->runtime())) {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWaitingOnGC().append(task)) {
ReportOutOfMemory(cx);
return false;
}
} else {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWorklist().append(task)) {
ReportOutOfMemory(cx);
return false;
}
task->activate(cx->runtime());
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
}
return true;
}
bool
js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
{
// Suppress GC so that calls below do not trigger a new incremental GC
// which could require barriers on the atoms compartment.
gc::AutoSuppressGC nogc(cx);
JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Script, nogc);
if (!global)
return false;
ScopedJSDeletePtr<ExclusiveContext> helpercx(
cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
ExclusiveContext::Context_Exclusive));
@@ -389,32 +472,50 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio
return false;
ScopedJSDeletePtr<ParseTask> task(
cx->new_<ParseTask>(helpercx.get(), global, cx, chars, length,
callback, callbackData));
cx->new_<ScriptParseTask>(helpercx.get(), global, cx, chars, length,
callback, callbackData));
if (!task)
return false;
helpercx.forget();
if (!task->init(cx, options))
if (!task->init(cx, options) || !QueueOffThreadParseTask(cx, task))
return false;
if (OffThreadParsingMustWaitForGC(cx->runtime())) {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWaitingOnGC().append(task.get())) {
ReportOutOfMemory(cx);
return false;
}
} else {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWorklist().append(task.get())) {
ReportOutOfMemory(cx);
return false;
}
task.forget();
task->activate(cx->runtime());
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
}
return true;
}
bool
js::StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData)
{
// Suppress GC so that calls below do not trigger a new incremental GC
// which could require barriers on the atoms compartment.
gc::AutoSuppressGC nogc(cx);
JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Module, nogc);
if (!global)
return false;
ScopedJSDeletePtr<ExclusiveContext> helpercx(
cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
ExclusiveContext::Context_Exclusive));
if (!helpercx)
return false;
ScopedJSDeletePtr<ParseTask> task(
cx->new_<ModuleParseTask>(helpercx.get(), global, cx, chars, length,
callback, callbackData));
if (!task)
return false;
helpercx.forget();
if (!task->init(cx, options) || !QueueOffThreadParseTask(cx, task))
return false;
task.forget();
@@ -1013,7 +1114,8 @@ LeaveParseTaskZone(JSRuntime* rt, ParseTask* task)
}
JSScript*
GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token)
GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, ParseTaskKind kind,
void* token)
{
ScopedJSDeletePtr<ParseTask> parseTask;
@@ -1031,6 +1133,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
}
}
MOZ_ASSERT(parseTask);
MOZ_ASSERT(parseTask->kind == kind);
if (!maybecx) {
LeaveParseTaskZone(rt, parseTask);
@@ -1043,7 +1146,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
// Make sure we have all the constructors we need for the prototype
// remapping below, since we can't GC while that's happening.
Rooted<GlobalObject*> global(cx, &cx->global()->as<GlobalObject>());
if (!EnsureParserCreatedClasses(cx)) {
if (!EnsureParserCreatedClasses(cx, kind)) {
LeaveParseTaskZone(rt, parseTask);
return nullptr;
}
@@ -1089,6 +1192,34 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void
return script;
}
JSScript*
GlobalHelperThreadState::finishScriptParseTask(JSContext* maybecx, JSRuntime* rt, void* token)
{
JSScript* script = finishParseTask(maybecx, rt, ParseTaskKind::Script, token);
MOZ_ASSERT_IF(script, script->isGlobalCode());
return script;
}
JSObject*
GlobalHelperThreadState::finishModuleParseTask(JSContext* maybecx, JSRuntime* rt, void* token)
{
JSScript* script = finishParseTask(maybecx, rt, ParseTaskKind::Module, token);
if (!script)
return nullptr;
MOZ_ASSERT(script->module());
if (!maybecx)
return nullptr;
JSContext* cx = maybecx;
RootedModuleObject module(cx, script->module());
module->fixScopesAfterCompartmentMerge(cx);
if (!ModuleObject::FreezeArrayProperties(cx, module))
return nullptr;
return module;
}
JSObject*
GlobalObject::getStarGeneratorFunctionPrototype()
{
@@ -1116,8 +1247,13 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* par
// Generator functions don't have Function.prototype as prototype but a
// different function object, so the IdentifyStandardPrototype trick
// below won't work. Just special-case it.
JSObject* parseTaskStarGenFunctionProto =
parseTask->exclusiveContextGlobal->as<GlobalObject>().getStarGeneratorFunctionPrototype();
GlobalObject* parseGlobal = &parseTask->exclusiveContextGlobal->as<GlobalObject>();
JSObject* parseTaskStarGenFunctionProto = parseGlobal->getStarGeneratorFunctionPrototype();
// Module objects don't have standard prototypes either.
JSObject* moduleProto = parseGlobal->maybeGetModulePrototype();
JSObject* importEntryProto = parseGlobal->maybeGetImportEntryPrototype();
JSObject* exportEntryProto = parseGlobal->maybeGetExportEntryPrototype();
// Point the prototypes of any objects in the script's compartment to refer
// to the corresponding prototype in the new compartment. This will briefly
@@ -1132,21 +1268,24 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* par
JSObject* protoObj = proto.toObject();
JSObject* newProto;
if (protoObj == parseTaskStarGenFunctionProto) {
newProto = global->getStarGeneratorFunctionPrototype();
} else {
JSProtoKey key = JS::IdentifyStandardPrototype(protoObj);
if (key == JSProto_Null)
continue;
JSProtoKey key = JS::IdentifyStandardPrototype(protoObj);
if (key != JSProto_Null) {
MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array ||
key == JSProto_Function || key == JSProto_RegExp ||
key == JSProto_Iterator);
newProto = GetBuiltinPrototypePure(global, key);
} else if (protoObj == parseTaskStarGenFunctionProto) {
newProto = global->getStarGeneratorFunctionPrototype();
} else if (protoObj == moduleProto) {
newProto = global->getModulePrototype();
} else if (protoObj == importEntryProto) {
newProto = global->getImportEntryPrototype();
} else if (protoObj == exportEntryProto) {
newProto = global->getExportEntryPrototype();
} else {
continue;
}
MOZ_ASSERT(newProto);
group->setProtoUnchecked(TaggedProto(newProto));
}
}
@@ -1387,25 +1526,7 @@ HelperThread::handleParseWorkload()
AutoUnlockHelperThreadState unlock;
PerThreadData::AutoEnterRuntime enter(threadData.ptr(),
task->exclusiveContextGlobal->runtimeFromAnyThread());
SourceBufferHolder srcBuf(task->chars, task->length,
SourceBufferHolder::NoOwnership);
// ! WARNING WARNING WARNING !
//
// See comment in Parser::bindLexical about optimizing global lexical
// bindings. If we start optimizing them, passing in task->cx's
// global lexical scope would be incorrect!
//
// ! WARNING WARNING WARNING !
ExclusiveContext* parseCx = task->cx;
Rooted<ClonedBlockObject*> globalLexical(parseCx, &parseCx->global()->lexicalScope());
Rooted<StaticScope*> staticScope(parseCx, &globalLexical->staticBlock());
task->script = frontend::CompileScript(parseCx, &task->alloc,
globalLexical, staticScope, nullptr,
task->options, srcBuf,
/* source_ = */ nullptr,
/* extraSct = */ nullptr,
/* sourceObjectOut = */ task->sourceObject.address());
task->parse();
}
// The callback is invoked while we are still off the main thread.
+38 -6
View File
@@ -37,6 +37,12 @@ namespace wasm {
typedef Vector<IonCompileTask*, 0, SystemAllocPolicy> IonCompileTaskVector;
} // namespace wasm
enum class ParseTaskKind
{
Script,
Module
};
// Per-process state for off thread work items.
class GlobalHelperThreadState
{
@@ -219,6 +225,11 @@ class GlobalHelperThreadState
return bool(numWasmFailedJobs);
}
JSScript* finishParseTask(JSContext* maybecx, JSRuntime* rt, ParseTaskKind kind, void* token);
void mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask,
Handle<GlobalObject*> global,
JSCompartment* dest);
private:
/*
* Number of wasm jobs that encountered failure for the active module.
@@ -227,10 +238,8 @@ class GlobalHelperThreadState
uint32_t numWasmFailedJobs;
public:
JSScript* finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token);
void mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask,
Handle<GlobalObject*> global,
JSCompartment* dest);
JSScript* finishScriptParseTask(JSContext* maybecx, JSRuntime* rt, void* token);
JSObject* finishModuleParseTask(JSContext* maybecx, JSRuntime* rt, void* token);
bool compressionInProgress(SourceCompressionTask* task);
SourceCompressionTask* compressionTaskForSource(ScriptSource* ss);
@@ -410,6 +419,11 @@ StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData);
bool
StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData);
/*
* Called at the end of GC to enqueue any Parse tasks that were waiting on an
* atoms-zone GC to finish.
@@ -463,6 +477,7 @@ class MOZ_RAII AutoUnlockHelperThreadState
struct ParseTask
{
ParseTaskKind kind;
ExclusiveContext* cx;
OwningCompileOptions options;
const char16_t* chars;
@@ -490,19 +505,36 @@ struct ParseTask
bool overRecursed;
bool outOfMemory;
ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData);
bool init(JSContext* cx, const ReadOnlyCompileOptions& options);
void activate(JSRuntime* rt);
virtual void parse() = 0;
bool finish(JSContext* cx);
bool runtimeMatches(JSRuntime* rt) {
return exclusiveContextGlobal->runtimeFromAnyThread() == rt;
}
~ParseTask();
virtual ~ParseTask();
};
struct ScriptParseTask : public ParseTask
{
ScriptParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData);
void parse() override;
};
struct ModuleParseTask : public ParseTask
{
ModuleParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal,
JSContext* initCx, const char16_t* chars, size_t length,
JS::OffThreadCompileCallback callback, void* callbackData);
void parse() override;
};
// Return whether, if a new parse task was started, it would need to wait for
+5
View File
@@ -1345,6 +1345,11 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
obj->as<ArgumentsObject>().markLengthOverridden();
}
if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
// Do same thing as .length for [@@iterator].
if ((desc_.attributes() & JSPROP_RESOLVING) == 0)
obj->as<ArgumentsObject>().markIteratorOverridden();
}
}
// 9.1.6.1 OrdinaryDefineOwnProperty steps 1-2.
+2 -20
View File
@@ -1028,10 +1028,10 @@ SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString
}
void
SavedStacks::sweep(JSRuntime* rt)
SavedStacks::sweep()
{
frames.sweep();
sweepPCLocationMap();
pcLocationMap.sweep();
}
void
@@ -1303,24 +1303,6 @@ SavedStacks::createFrameFromLookup(JSContext* cx, SavedFrame::HandleLookup looku
return frame;
}
/*
* Remove entries from the table whose JSScript is being collected.
*/
void
SavedStacks::sweepPCLocationMap()
{
for (PCLocationMap::Enum e(pcLocationMap); !e.empty(); e.popFront()) {
PCKey key = e.front().key();
JSScript* script = key.script.get();
if (IsAboutToBeFinalizedUnbarriered(&script)) {
e.removeFront();
} else if (script != key.script.get()) {
key.script = script;
e.rekeyFront(key);
}
}
}
bool
SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
MutableHandle<LocationValue> locationp)
+19 -16
View File
@@ -167,7 +167,7 @@ class SavedStacks {
bool saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame, unsigned maxFrameCount = 0);
bool copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
MutableHandleSavedFrame adoptedStack, unsigned maxFrameCount = 0);
void sweep(JSRuntime* rt);
void sweep();
void trace(JSTracer* trc);
uint32_t count();
void clear();
@@ -220,28 +220,32 @@ class SavedStacks {
struct PCKey {
PCKey(JSScript* script, jsbytecode* pc) : script(script), pc(pc) { }
PreBarrieredScript script;
jsbytecode* pc;
RelocatablePtrScript script;
jsbytecode* pc;
bool needsSweep() { return IsAboutToBeFinalized(&script); }
};
public:
struct LocationValue {
LocationValue() : source(nullptr), line(0), column(0) { }
LocationValue(JSAtom* source, size_t line, uint32_t column)
: source(source),
line(line),
column(column)
: source(source), line(line), column(column)
{ }
static void trace(LocationValue* self, JSTracer* trc) { self->trace(trc); }
void trace(JSTracer* trc) {
if (source)
TraceEdge(trc, &source, "SavedStacks::LocationValue::source");
}
PreBarrieredAtom source;
size_t line;
uint32_t column;
bool needsSweep() {
MOZ_ASSERT(source);
return !IsAboutToBeFinalized(&source);
}
RelocatablePtrAtom source;
size_t line;
uint32_t column;
};
template <typename Outer>
@@ -264,8 +268,8 @@ class SavedStacks {
private:
struct PCLocationHasher : public DefaultHasher<PCKey> {
typedef PointerHasher<JSScript*, 3> ScriptPtrHasher;
typedef PointerHasher<jsbytecode*, 3> BytecodePtrHasher;
using ScriptPtrHasher = DefaultHasher<JSScript*>;
using BytecodePtrHasher = DefaultHasher<jsbytecode*>;
static HashNumber hash(const PCKey& key) {
return mozilla::AddToHash(ScriptPtrHasher::hash(key.script),
@@ -273,15 +277,14 @@ class SavedStacks {
}
static bool match(const PCKey& l, const PCKey& k) {
return l.script == k.script && l.pc == k.pc;
return ScriptPtrHasher::match(l.script, k.script) &&
BytecodePtrHasher::match(l.pc, k.pc);
}
};
typedef HashMap<PCKey, LocationValue, PCLocationHasher, SystemAllocPolicy> PCLocationMap;
using PCLocationMap = GCHashMap<PCKey, LocationValue, PCLocationHasher, SystemAllocPolicy>;
PCLocationMap pcLocationMap;
void sweepPCLocationMap();
bool getLocation(JSContext* cx, const FrameIter& iter, MutableHandle<LocationValue> locationp);
};
+13
View File
@@ -1479,6 +1479,13 @@ ScopeIter::settle()
if (frame_ && frame_.isFunctionFrame() && frame_.callee()->needsCallObject() &&
!frame_.hasCallObj())
{
// At the very start of a script that starts with a lexical block, the
// static scope will be that block. Skip it if this is the case.
if (ssi_.type() == StaticScopeIter<CanGC>::Block)
incrementStaticScopeIter();
// We should now be at the function scope, so since we have no
// CallObject, skip that too.
MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Function);
incrementStaticScopeIter();
}
@@ -1486,8 +1493,14 @@ ScopeIter::settle()
// Check for trying to iterate a strict eval frame before the prologue has
// created the CallObject.
if (frame_ && frame_.isStrictEvalFrame() && !frame_.hasCallObj() && !ssi_.done()) {
// Eval frames always have their own lexical scope. Analogous to the
// function frame case above, if the script starts with a lexical
// block, the SSI could see 2 block scopes here. So skip between 1-2
// static block scopes here.
MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Block);
incrementStaticScopeIter();
if (ssi_.type() == StaticScopeIter<CanGC>::Block)
incrementStaticScopeIter();
MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Eval);
MOZ_ASSERT(maybeStaticScope() == frame_.script()->enclosingStaticScope());
incrementStaticScopeIter();
+93
View File
@@ -780,6 +780,64 @@ intrinsic_ArrayBufferCopyData(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_IsSpecificTypedArray(JSContext* cx, unsigned argc, Value* vp, Scalar::Type type)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
JSObject* obj = &args[0].toObject();
bool isArray = JS_GetArrayBufferViewType(obj) == type;
args.rval().setBoolean(isArray);
return true;
}
static bool
intrinsic_IsUint8TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint8) ||
intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint8Clamped);
}
static bool
intrinsic_IsInt8TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int8);
}
static bool
intrinsic_IsUint16TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint16);
}
static bool
intrinsic_IsInt16TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int16);
}
static bool
intrinsic_IsUint32TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint32);
}
static bool
intrinsic_IsInt32TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int32);
}
static bool
intrinsic_IsFloat32TypedArray(JSContext* cx, unsigned argc, Value* vp)
{
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Float32);
}
static bool
intrinsic_IsPossiblyWrappedTypedArray(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1327,6 +1385,34 @@ CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc, Value* vp)
return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args);
}
bool
js::IsCallSelfHostedNonGenericMethod(NativeImpl impl)
{
return impl == CallSelfHostedNonGenericMethod;
}
bool
js::ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args)
{
// The contract for this function is the same as CallSelfHostedNonGenericMethod.
// The normal ReportIncompatible function doesn't work for selfhosted functions,
// because they always call the different CallXXXMethodIfWrapped methods,
// which would be reported as the called function instead.
// Lookup the selfhosted method that was invoked.
ScriptFrameIter iter(cx);
MOZ_ASSERT(iter.isFunctionFrame());
JSAutoByteString funNameBytes;
if (const char* funName = GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
funName, "method", InformalValueTypeName(args.thisv()));
}
return false;
}
/**
* Returns the default locale as a well-formed, but not necessarily canonicalized,
* BCP-47 language tag.
@@ -1768,6 +1854,13 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("ArrayBufferByteLength", intrinsic_ArrayBufferByteLength, 1,0),
JS_FN("ArrayBufferCopyData", intrinsic_ArrayBufferCopyData, 4,0),
JS_FN("IsUint8TypedArray", intrinsic_IsUint8TypedArray, 1,0),
JS_FN("IsInt8TypedArray", intrinsic_IsInt8TypedArray, 1,0),
JS_FN("IsUint16TypedArray", intrinsic_IsUint16TypedArray, 1,0),
JS_FN("IsInt16TypedArray", intrinsic_IsInt16TypedArray, 1,0),
JS_FN("IsUint32TypedArray", intrinsic_IsUint32TypedArray, 1,0),
JS_FN("IsInt32TypedArray", intrinsic_IsInt32TypedArray, 1,0),
JS_FN("IsFloat32TypedArray", intrinsic_IsFloat32TypedArray, 1,0),
JS_INLINABLE_FN("IsTypedArray",
intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1,0,
IntrinsicIsTypedArray),
+9 -1
View File
@@ -8,6 +8,7 @@
#define vm_SelfHosting_h_
#include "jsapi.h"
#include "NamespaceImports.h"
class JSAtom;
@@ -17,7 +18,14 @@ namespace js {
* Check whether the given JSFunction is a self-hosted function whose
* self-hosted name is the given name.
*/
bool IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
bool
IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
bool
IsCallSelfHostedNonGenericMethod(NativeImpl impl);
bool
ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args);
/* Get the compile options used when compiling self hosted code. */
void
+12 -4
View File
@@ -164,15 +164,15 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
void
SharedArrayRawBuffer::addReference()
{
MOZ_ASSERT(this->refcount > 0);
++this->refcount; // Atomic.
MOZ_ASSERT(this->refcount_ > 0);
++this->refcount_; // Atomic.
}
void
SharedArrayRawBuffer::dropReference()
{
// Drop the reference to the buffer.
uint32_t refcount = --this->refcount; // Atomic.
uint32_t refcount = --this->refcount_; // Atomic.
// If this was the final reference, release the buffer.
if (refcount == 0) {
@@ -330,7 +330,15 @@ SharedArrayBufferObject::Finalize(FreeOp* fop, JSObject* obj)
SharedArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
JS::ClassInfo* info)
{
info->objectsNonHeapElementsMapped += obj->as<SharedArrayBufferObject>().byteLength();
// Divide the buffer size by the refcount to get the fraction of the buffer
// owned by this thread. It's conceivable that the refcount might change in
// the middle of memory reporting, in which case the amount reported for
// some threads might be to high (if the refcount goes up) or too low (if
// the refcount goes down). But that's unlikely and hard to avoid, so we
// just live with the risk.
const SharedArrayBufferObject& buf = obj->as<SharedArrayBufferObject>();
info->objectsNonHeapElementsShared +=
buf.byteLength() / buf.rawBufferObject()->refcount();
}
const Class SharedArrayBufferObject::protoClass = {
+4 -2
View File
@@ -44,7 +44,7 @@ class FutexWaiter;
class SharedArrayRawBuffer
{
private:
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount;
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_;
uint32_t length;
// A list of structures representing tasks waiting on some
@@ -53,7 +53,7 @@ class SharedArrayRawBuffer
protected:
SharedArrayRawBuffer(uint8_t* buffer, uint32_t length)
: refcount(1),
: refcount_(1),
length(length),
waiters_(nullptr)
{
@@ -84,6 +84,8 @@ class SharedArrayRawBuffer
return length;
}
uint32_t refcount() const { return refcount_; }
void addReference();
void dropReference();
};
+1
View File
@@ -18,6 +18,7 @@
#include "js/GCAPI.h"
#include "vm/Debugger.h"
#include "vm/Opcodes.h"
#include "vm/ScopeObject.h"
#include "jit/JitFrameIterator-inl.h"
#include "vm/Interpreter-inl.h"
+16 -8
View File
@@ -2166,10 +2166,10 @@ ReportClassStats(const ClassInfo& classInfo, const nsACString& path,
"Non-fixed object slots.");
}
if (classInfo.objectsMallocHeapElementsNonAsmJS > 0) {
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/elements/non-asm.js"),
KIND_HEAP, classInfo.objectsMallocHeapElementsNonAsmJS,
"Non-asm.js indexed elements.");
if (classInfo.objectsMallocHeapElementsNormal > 0) {
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/elements/normal"),
KIND_HEAP, classInfo.objectsMallocHeapElementsNormal,
"Normal (non-asm.js) indexed elements.");
}
// asm.js arrays are heap-allocated on some platforms and
@@ -2192,10 +2192,18 @@ ReportClassStats(const ClassInfo& classInfo, const nsACString& path,
"the GC heap.");
}
if (classInfo.objectsNonHeapElementsMapped > 0) {
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/mapped"),
KIND_NONHEAP, classInfo.objectsNonHeapElementsMapped,
"Memory-mapped array buffer elements.");
if (classInfo.objectsNonHeapElementsNormal > 0) {
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/normal"),
KIND_NONHEAP, classInfo.objectsNonHeapElementsNormal,
"Memory-mapped non-shared array buffer elements.");
}
if (classInfo.objectsNonHeapElementsShared > 0) {
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/shared"),
KIND_NONHEAP, classInfo.objectsNonHeapElementsShared,
"Memory-mapped shared array buffer elements. These elements are "
"shared between one or more runtimes; the reported size is divided "
"by the buffer's refcount.");
}
if (classInfo.objectsNonHeapCodeAsmJS > 0) {
+7 -1
View File
@@ -123,7 +123,10 @@ FramePropertyTable::RemoveInternal(
if (entry->mProp.mProperty == aProperty) {
// There's only one entry and it's the one we want
void* value = entry->mProp.mValue;
mEntries.RawRemoveEntry(entry);
// Here it's ok to use RemoveEntry() -- which may resize mEntries --
// because we null mLastEntry at the same time.
mEntries.RemoveEntry(entry);
mLastEntry = nullptr;
if (aFoundResult) {
*aFoundResult = true;
@@ -209,6 +212,9 @@ FramePropertyTable::DeleteAllFor(const nsIFrame* aFrame)
}
DeleteAllForEntry(entry);
// mLastEntry points into mEntries, so we use RawRemoveEntry() which will not
// resize mEntries.
mEntries.RawRemoveEntry(entry);
}
+3
View File
@@ -347,6 +347,9 @@ protected:
static void DeleteAllForEntry(Entry* aEntry);
// Note that mLastEntry points into mEntries, so we need to be careful about
// not triggering a resize of mEntries, e.g. use RawRemoveEntry() instead of
// RemoveEntry() in some places.
nsTHashtable<Entry> mEntries;
const nsIFrame* mLastFrame;
Entry* mLastEntry;
+3 -2
View File
@@ -1194,8 +1194,9 @@ inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames)
{
nsTArray<nsIAtom*> array;
const uint8_t pseudoCount = static_cast<uint8_t>(CSSPseudoElementType::Count);
for (uint8_t i = 0; i < pseudoCount; ++i) {
const CSSPseudoElementTypeBase pseudoCount =
static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count);
for (CSSPseudoElementTypeBase i = 0; i < pseudoCount; ++i) {
CSSPseudoElementType type = static_cast<CSSPseudoElementType>(i);
if (!nsCSSPseudoElements::PseudoElementIsUASheetOnly(type)) {
nsIAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type);
+1
View File
@@ -664,6 +664,7 @@ BrotliDecoderDecompress
BrotliDecoderStateInit
BrotliDecoderStateCleanup
BrotliDecoderDecompressStream
BrotliDecoderIsFinished
#ifdef MOZ_WEBRTC
downmix_int
#ifdef MOZ_SAMPLE_TYPE_FLOAT32
+1 -1
View File
@@ -5,6 +5,6 @@
<title>Inline blocks shouldn't end the paragraph</title>
</head>
<body>
<p>&#x202e;אני אוהב--&gt; 4 xoferiF--&gt;8 ימים בשבוע</p>
<p>&#x202e;ימים בשבוע 8&lt;-- 4 xoferiF&lt;--אני אוהב</p>
</body>
</html>
+1 -1
View File
@@ -5,6 +5,6 @@
<title>Facebook</title>
</head>
<body dir="rtl">
<div style="font-size: 18pt; letter-spacing: 2pt;">Winnie the Pooh commented on his own קישור on Christopher Robin's wall: "Lorem ipsum dolor sit amet"</div>
<div style="font-size: 18pt; letter-spacing: 2pt;"><bdi>Winnie the Pooh</bdi> commented on his own קישור on <bdi>Christopher Robin</bdi>'s <bdi>wall</bdi>: "<bdi>Lorem ipsum dolor sit amet</bdi>"</div>
</body>
</html>
-33
View File
@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Bidirectional Text Test 2 - HTML</title>
<style>
p { font-family: monospace; text-align: left; }
.embed { unicode-bidi: embed; }
.override { unicode-bidi: bidi-override; }
.rtl { direction: rtl; }
.ltr { direction: ltr; }
</style>
</head>
<!-- Testcases based on http://dbaron.org/css/test/bidi2_html by L. David Baron. -->
<body>
<p>&#x05D0;&#x05D1;&#x05D2;</p>
<p class="embed">&#x05D0;&#x05D1;&#x05D2;</p>
<p class="override">&#x05D0;&#x05D1;&#x05D2;</p>
<p>&#x05D0;&#x05D1;&#x05D2; ABC &#x05D3;&#x05D4;&#x05D5;</p>
<p class="rtl">&#x05D0;&#x05D1;&#x05D2; ABC &#x05D3;&#x05D4;&#x05D5;</p>
<p>&#x05D0;&#x05D1;&#x05D2; ABC &#x05D3;&#x05D4;&#x05D5; DEF &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <span>ABC &#x05D3;&#x05D4;&#x05D5;</span> DEF &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <span dir="ltr">ABC &#x05D3;&#x05D4;&#x05D5; DEF</span> &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <span dir="rtl">ABC &#x05D3;&#x05D4;&#x05D5; DEF</span> &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <span dir="rtl">ABC &#x05D3;&#x05D4;&#x05D5;</span> DEF &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <bdo dir="rtl">ABC &#x05D3;&#x05D4;&#x05D5;</bdo> DEF &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <bdo dir="ltr">ABC &#x05D3;&#x05D4;&#x05D5;</bdo> DEF &#x05D6;&#x05D7;&#x05D8;</p>
<p class="rtl">&#x05D0;&#x05D1;&#x05D2; <bdo dir="ltr">ABC &#x05D3;&#x05D4;&#x05D5;</bdo> DEF &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; ABC &#x05D3;&#x05D4;&#x05D5; DEF GHI &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; <bdo dir="rtl">ABC &#x05D3;&#x05D4;&#x05D5; DEF</bdo> GHI &#x05D6;&#x05D7;&#x05D8;</p>
<p>&#x05D0;&#x05D1;&#x05D2; ABC <bdo dir="rtl">&#x05D3;&#x05D4;&#x05D5; DEF</bdo> GHI &#x05D6;&#x05D7;&#x05D8;</p>
</body>
</html>
+1 -2
View File
@@ -52,7 +52,6 @@ random-if(cocoaWidget) == with-first-letter-2b.html with-first-letter-2-ref.html
== 83958-1c.html 83958-1-ref.html
fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,111,7) == 83958-2a.html 83958-2-ref.html
fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,111,7) == 83958-2b.html 83958-2-ref.html
fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,111,7) == 83958-2c.html 83958-2-ref.html
== 115921-1.html 115921-1-ref.html
== 115921-2.html 115921-2-ref.html
== 151407-1.html 151407-1-ref.html
@@ -74,7 +73,7 @@ fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azur
== 263359-1a.html 263359-1-ref.html
!= 263359-1b.html 263359-1-ref.html
== 263359-2.html 263359-2-ref.html
== 263359-3.html 263359-3-ref.html
fails == 263359-3.html 263359-3-ref.html # bug 1230455
== 263359-4.html 263359-4-ref.html
random-if(winWidget) == 267459-1.html 267459-1-ref.html # depends on windows version, see bug 590101
== 267459-2.html 267459-2-ref.html
+2 -4
View File
@@ -314,11 +314,9 @@ nsCSSSelector::nsCSSSelector(void)
mNext(nullptr),
mNameSpace(kNameSpaceID_Unknown),
mOperator(0),
mPseudoType(static_cast<int16_t>(CSSPseudoElementType::NotPseudo))
mPseudoType(CSSPseudoElementType::NotPseudo)
{
MOZ_COUNT_CTOR(nsCSSSelector);
static_assert(static_cast<int16_t>(CSSPseudoElementType::MAX) < INT16_MAX,
"CSSPseudoElementType values overflow mPseudoType");
}
nsCSSSelector*
@@ -333,7 +331,7 @@ nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
result->mCasedTag = mCasedTag;
result->mOperator = mOperator;
result->mPseudoType = mPseudoType;
NS_IF_CLONE(mIDList);
NS_IF_CLONE(mClassList);
NS_IF_CLONE(mPseudoClassList);
+6 -6
View File
@@ -25,6 +25,7 @@ class nsIAtom;
struct nsCSSSelectorList;
namespace mozilla {
enum class CSSPseudoElementType : uint8_t;
class CSSStyleSheet;
} // namespace mozilla
@@ -208,11 +209,9 @@ private:
public:
// Get and set the selector's pseudo type
mozilla::CSSPseudoElementType PseudoType() const {
return static_cast<mozilla::CSSPseudoElementType>(mPseudoType);
}
mozilla::CSSPseudoElementType PseudoType() const { return mPseudoType; }
void SetPseudoType(mozilla::CSSPseudoElementType aType) {
mPseudoType = static_cast<int16_t>(aType);
mPseudoType = aType;
}
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@@ -233,8 +232,9 @@ public:
int32_t mNameSpace;
char16_t mOperator;
private:
// int16_t to make sure it packs well with mOperator
int16_t mPseudoType;
// The underlying type of CSSPseudoElementType is uint8_t and
// it packs well with mOperator. (char16_t + uint8_t is less than 32bits.)
mozilla::CSSPseudoElementType mPseudoType;
nsCSSSelector(const nsCSSSelector& aCopy) = delete;
nsCSSSelector& operator=(const nsCSSSelector& aCopy) = delete;
+57 -56
View File
@@ -7,13 +7,14 @@
/* bidi */
[dir] {
unicode-bidi: -moz-isolate;
}
[dir="rtl"] {
direction: rtl;
unicode-bidi: embed;
}
[dir="ltr"] {
direction: ltr;
unicode-bidi: embed;
}
bdi:-moz-dir(ltr), [dir="auto"]:-moz-dir(ltr) { direction: ltr; }
@@ -30,62 +31,62 @@ bdi:-moz-dir(rtl), [dir="auto"]:-moz-dir(rtl) { direction: rtl; }
* and the rules in http://dev.w3.org/html5/spec/rendering.html#rendering
*/
address, address[dir],
article, article[dir],
aside, aside[dir],
blockquote, blockquote[dir],
body, body[dir],
caption, caption[dir],
center, center[dir],
col, col[dir],
colgroup, colgroup[dir],
dd, dd[dir],
dir, dir[dir],
div, div[dir],
dl, dl[dir],
dt, dt[dir],
fieldset, fieldset[dir],
figcaption, figcaption[dir],
figure, figure[dir],
footer, footer[dir],
form, form[dir],
h1, h1[dir],
h2, h2[dir],
h3, h3[dir],
h4, h4[dir],
h5, h5[dir],
h6, h6[dir],
header, header[dir],
hgroup, hgroup[dir],
hr, hr[dir],
html, html[dir],
legend, legend[dir],
li, li[dir],
listing, listing[dir],
main, main[dir],
marquee, marquee[dir],
menu, menu[dir],
nav, nav[dir],
noframes, noframes[dir],
ol, ol[dir],
p, p[dir],
plaintext, plaintext[dir],
pre, pre[dir],
section, section[dir],
summary, summary[dir],
table, table[dir],
tbody, tbody[dir],
td, td[dir],
tfoot, tfoot[dir],
th, th[dir],
thead, thead[dir],
tr, tr[dir],
ul, ul[dir],
xmp, xmp[dir] {
address,
article,
aside,
blockquote,
body,
caption,
center,
col,
colgroup,
dd,
dir,
div,
dl,
dt,
fieldset,
figcaption,
figure,
footer,
form,
h1,
h2,
h3,
h4,
h5,
h6,
header,
hgroup,
hr,
html,
legend,
li,
listing,
main,
marquee,
menu,
nav,
noframes,
ol,
p,
plaintext,
pre,
section,
summary,
table,
tbody,
td,
tfoot,
th,
thead,
tr,
ul,
xmp {
unicode-bidi: -moz-isolate;
}
bdi, bdi[dir], output, output[dir], [dir="auto"] {
bdi, output {
unicode-bidi: -moz-isolate;
}
bdo, bdo[dir] {
@@ -724,7 +725,7 @@ area {
display: none ! important;
}
iframe:-moz-full-screen {
iframe:fullscreen {
/* iframes in full-screen mode don't show a border. */
border: none !important;
padding: 0 !important;
+1
View File
@@ -163,6 +163,7 @@ CSS_STATE_PSEUDO_CLASS(mozDevtoolsHighlighted, ":-moz-devtools-highlighted", 0,
// Matches the element which is being displayed full-screen, and
// any containing frames.
CSS_STATE_PSEUDO_CLASS(fullscreen, ":fullscreen", 0, "", NS_EVENT_STATE_FULL_SCREEN)
CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", 0, "", NS_EVENT_STATE_FULL_SCREEN)
// Matches any element which is an ancestor of the DOM full-screen element,
+6 -3
View File
@@ -76,7 +76,9 @@ nsCSSPseudoElements::IsCSS2PseudoElement(nsIAtom *aAtom)
/* static */ CSSPseudoElementType
nsCSSPseudoElements::GetPseudoType(nsIAtom *aAtom)
{
for (uint8_t i = 0; i < ArrayLength(CSSPseudoElements_info); ++i) {
for (CSSPseudoElementTypeBase i = 0;
i < ArrayLength(CSSPseudoElements_info);
++i) {
if (*CSSPseudoElements_info[i].mAtom == aAtom) {
return static_cast<Type>(i);
}
@@ -99,13 +101,14 @@ nsCSSPseudoElements::GetPseudoType(nsIAtom *aAtom)
nsCSSPseudoElements::GetPseudoAtom(Type aType)
{
NS_ASSERTION(aType < Type::Count, "Unexpected type");
return *CSSPseudoElements_info[static_cast<uint8_t>(aType)].mAtom;
return *CSSPseudoElements_info[
static_cast<CSSPseudoElementTypeBase>(aType)].mAtom;
}
/* static */ uint32_t
nsCSSPseudoElements::FlagsForPseudoElement(const Type aType)
{
uint8_t index = static_cast<uint8_t>(aType);
CSSPseudoElementTypeBase index = static_cast<CSSPseudoElementTypeBase>(aType);
NS_ASSERTION(index < ArrayLength(CSSPseudoElements_flags),
"argument must be a pseudo-element");
return CSSPseudoElements_flags[index];
+2 -1
View File
@@ -39,7 +39,8 @@ namespace mozilla {
// The total count of CSSPseudoElement is less than 256,
// so use uint8_t as its underlying type.
enum class CSSPseudoElementType : uint8_t {
typedef uint8_t CSSPseudoElementTypeBase;
enum class CSSPseudoElementType : CSSPseudoElementTypeBase {
// If the actual pseudo-elements stop being first here, change
// GetPseudoType.
#define CSS_PSEUDO_ELEMENT(_name, _value_, _flags) \
+6 -7
View File
@@ -910,8 +910,8 @@ struct RuleCascadeData {
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
RuleHash mRuleHash;
RuleHash*
mPseudoElementRuleHashes[static_cast<uint8_t>(CSSPseudoElementType::Count)];
RuleHash* mPseudoElementRuleHashes[
static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count)];
nsTArray<nsCSSRuleProcessor::StateSelector> mStateSelectors;
EventStates mSelectorDocumentStates;
PLDHashTable mClassSelectors;
@@ -2645,9 +2645,8 @@ nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData)
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
if (cascade) {
RuleHash* ruleHash =
cascade->mPseudoElementRuleHashes[static_cast<uint8_t>(
aData->mPseudoType)];
RuleHash* ruleHash = cascade->mPseudoElementRuleHashes[
static_cast<CSSPseudoElementTypeBase>(aData->mPseudoType)];
if (ruleHash) {
NodeMatchContext nodeContext(EventStates(),
nsCSSRuleProcessor::IsLink(aData->mElement));
@@ -3416,8 +3415,8 @@ AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade)
if (MOZ_LIKELY(pseudoType == CSSPseudoElementType::NotPseudo)) {
cascade->mRuleHash.AppendRule(*aRuleInfo);
} else if (pseudoType < CSSPseudoElementType::Count) {
RuleHash*& ruleHash =
cascade->mPseudoElementRuleHashes[static_cast<uint8_t>(pseudoType)];
RuleHash*& ruleHash = cascade->mPseudoElementRuleHashes[
static_cast<CSSPseudoElementTypeBase>(pseudoType)];
if (!ruleHash) {
ruleHash = new RuleHash(cascade->mQuirksMode);
if (!ruleHash) {
+2 -1
View File
@@ -90,7 +90,8 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent,
// This check has to be done "backward", because if it were written the
// more natural way it wouldn't fail even when it needed to.
static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
static_cast<uint8_t>(CSSPseudoElementType::MAX),
static_cast<CSSPseudoElementTypeBase>(
CSSPseudoElementType::MAX),
"pseudo element bits no longer fit in a uint64_t");
MOZ_ASSERT(aRuleNode);
+6 -6
View File
@@ -32,10 +32,10 @@ var tests = [
['div', {'dir': ''}, 'ltr', '-moz-isolate'],
['span', {}, 'ltr', 'normal'],
['span', {'dir': 'ltr'}, 'ltr', 'embed'],
['span', {'dir': 'rtl'}, 'rtl', 'embed'],
['span', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
['span', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
['span', {'dir': 'auto'}, 'ltr', '-moz-isolate'],
['span', {'dir': ''}, 'ltr', 'normal'],
['span', {'dir': ''}, 'ltr', '-moz-isolate'],
['bdi', {}, 'ltr', '-moz-isolate'],
['bdi', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
@@ -56,10 +56,10 @@ var tests = [
['bdo', {'dir': ''}, 'ltr', 'bidi-override'],
['textarea', {}, 'ltr', 'normal'],
['textarea', {'dir': 'ltr'}, 'ltr', 'embed'],
['textarea', {'dir': 'rtl'}, 'rtl', 'embed'],
['textarea', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
['textarea', {'dir': 'rtl'}, 'rtl', '-moz-isolate'],
['textarea', {'dir': 'auto'}, 'ltr', '-moz-plaintext'],
['textarea', {'dir': ''}, 'ltr', 'normal'],
['textarea', {'dir': ''}, 'ltr', '-moz-isolate'],
['pre', {}, 'ltr', '-moz-isolate'],
['pre', {'dir': 'ltr'}, 'ltr', '-moz-isolate'],
+2 -2
View File
@@ -276,7 +276,7 @@
}
*|*:-moz-full-screen:not(:root) {
*|*:fullscreen:not(:root) {
position: fixed !important;
top: 0 !important;
left: 0 !important;
@@ -296,7 +296,7 @@
/* Selectors here should match the check in
* nsViewportFrame.cpp:ShouldInTopLayerForFullscreen() */
*|*:-moz-full-screen:not(:root):not(:-moz-browser-frame) {
*|*:fullscreen:not(:root):not(:-moz-browser-frame) {
-moz-top-layer: top !important;
}
@@ -50,16 +50,6 @@ ClearKeySessionManager::~ClearKeySessionManager()
CK_LOGD("ClearKeySessionManager dtor %p", this);
}
static bool
ShouldBeAbleToDecode()
{
#if !defined(ENABLE_WMF)
return false;
#else
return IsWindowsVistaOrGreater();
#endif
}
static bool
CanDecode()
{
@@ -75,17 +65,12 @@ ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback)
{
CK_LOGD("ClearKeySessionManager::Init");
mCallback = aCallback;
if (ShouldBeAbleToDecode()) {
if (!CanDecode()) {
const char* err = "EME plugin can't load system decoder!";
mCallback->SessionError(nullptr, 0, kGMPAbortError, 0, err, strlen(err));
} else {
mCallback->SetCapabilities(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO |
GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO);
}
} else {
if (!CanDecode()) {
mCallback->SetCapabilities(GMP_EME_CAP_DECRYPT_AUDIO |
GMP_EME_CAP_DECRYPT_VIDEO);
} else {
mCallback->SetCapabilities(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO |
GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO);
}
ClearKeyPersistence::EnsureInitialized();
}

Some files were not shown because too many files have changed in this diff Show More