mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:11:03 +00:00
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:
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -114,6 +114,7 @@ private:
|
||||
static StaticRefPtr<nsIThreadPool> sThreadPool;
|
||||
|
||||
friend class EncodingRunnable;
|
||||
friend class EncoderThreadPoolTerminator;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
|
||||
if (entry) {
|
||||
entry->RemoveIdElement(aElement);
|
||||
if (entry->IsEmpty()) {
|
||||
mIdentifierMap.RawRemoveEntry(entry);
|
||||
mIdentifierMap.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -439,6 +439,12 @@ WifiCertService::WifiCertService()
|
||||
WifiCertService::~WifiCertService()
|
||||
{
|
||||
MOZ_ASSERT(!gWifiCertService);
|
||||
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown()) {
|
||||
return;
|
||||
}
|
||||
shutdown(calledFromObject);
|
||||
}
|
||||
|
||||
already_AddRefed<WifiCertService>
|
||||
|
||||
@@ -1831,7 +1831,7 @@ XULDocument::RemoveElementFromRefMap(Element* aElement)
|
||||
if (!entry)
|
||||
return;
|
||||
if (entry->RemoveElement(aElement)) {
|
||||
mRefMap.RawRemoveEntry(entry);
|
||||
mRefMap.RemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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) \
|
||||
\
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
}
|
||||
@@ -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) {}
|
||||
} + ")()");
|
||||
@@ -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);
|
||||
} + ")()")
|
||||
})();
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
if (!('oomTest' in this))
|
||||
quit();
|
||||
|
||||
function arrayProtoOutOfRange() {
|
||||
for (let [] = () => r, get;;)
|
||||
var r = f(i % 2 ? a : b);
|
||||
}
|
||||
oomTest(arrayProtoOutOfRange);
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -664,6 +664,7 @@ BrotliDecoderDecompress
|
||||
BrotliDecoderStateInit
|
||||
BrotliDecoderStateCleanup
|
||||
BrotliDecoderDecompressStream
|
||||
BrotliDecoderIsFinished
|
||||
#ifdef MOZ_WEBRTC
|
||||
downmix_int
|
||||
#ifdef MOZ_SAMPLE_TYPE_FLOAT32
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<title>Inline blocks shouldn't end the paragraph</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>‮אני אוהב--> 4 xoferiF-->8 ימים בשבוע</p>
|
||||
<p>‮ימים בשבוע 8<-- 4 xoferiF<--אני אוהב</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>אבג</p>
|
||||
<p class="embed">אבג</p>
|
||||
<p class="override">אבג</p>
|
||||
<p>אבג ABC דהו</p>
|
||||
<p class="rtl">אבג ABC דהו</p>
|
||||
<p>אבג ABC דהו DEF זחט</p>
|
||||
<p>אבג <span>ABC דהו</span> DEF זחט</p>
|
||||
<p>אבג <span dir="ltr">ABC דהו DEF</span> זחט</p>
|
||||
<p>אבג <span dir="rtl">ABC דהו DEF</span> זחט</p>
|
||||
<p>אבג <span dir="rtl">ABC דהו</span> DEF זחט</p>
|
||||
<p>אבג <bdo dir="rtl">ABC דהו</bdo> DEF זחט</p>
|
||||
<p>אבג <bdo dir="ltr">ABC דהו</bdo> DEF זחט</p>
|
||||
<p class="rtl">אבג <bdo dir="ltr">ABC דהו</bdo> DEF זחט</p>
|
||||
<p>אבג ABC דהו DEF GHI זחט</p>
|
||||
<p>אבג <bdo dir="rtl">ABC דהו DEF</bdo> GHI זחט</p>
|
||||
<p>אבג ABC <bdo dir="rtl">דהו DEF</bdo> GHI זחט</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user