зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to autoland. a=merge
This commit is contained in:
Коммит
7e1a57cfa4
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1343682 - backing out a previous version didn't stop the failures from it, so it appears to need a clobber both out and in
|
||||
Bug 1265818 - deleted an exported header and added a new .idl to regenerate that same header; and this unfortunately produces an untracked generated header in your source dir whenever you build (probably due to a dangling symlink), unless you clobber
|
||||
|
|
|
@ -867,7 +867,7 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
|||
continue;
|
||||
}
|
||||
|
||||
ipcDoc = new DocAccessibleChild(childDoc);
|
||||
ipcDoc = new DocAccessibleChild(childDoc, parentIPCDoc->Manager());
|
||||
childDoc->SetIPCDoc(ipcDoc);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
|
|
@ -1482,7 +1482,7 @@ DocAccessible::DoInitialUpdate()
|
|||
if (IPCAccessibilityActive()) {
|
||||
nsIDocShell* docShell = mDocumentNode->GetDocShell();
|
||||
if (RefPtr<dom::TabChild> tabChild = dom::TabChild::GetFrom(docShell)) {
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(this);
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(this, tabChild);
|
||||
SetIPCDoc(ipcDoc);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
|
|
@ -26,10 +26,11 @@ class TableCellAccessible;
|
|||
class DocAccessibleChild : public DocAccessibleChildBase
|
||||
{
|
||||
public:
|
||||
explicit DocAccessibleChild(DocAccessible* aDoc)
|
||||
DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
|
||||
: DocAccessibleChildBase(aDoc)
|
||||
{
|
||||
MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
|
||||
SetManager(aManager);
|
||||
}
|
||||
|
||||
~DocAccessibleChild()
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace a11y {
|
|||
|
||||
static StaticAutoPtr<PlatformChild> sPlatformChild;
|
||||
|
||||
DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
|
||||
DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager)
|
||||
: DocAccessibleChildBase(aDoc)
|
||||
, mEmulatedWindowHandle(nullptr)
|
||||
, mIsRemoteConstructed(false)
|
||||
|
@ -26,6 +26,8 @@ DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
|
|||
sPlatformChild = new PlatformChild();
|
||||
ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown);
|
||||
}
|
||||
|
||||
SetManager(aManager);
|
||||
}
|
||||
|
||||
DocAccessibleChild::~DocAccessibleChild()
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace a11y {
|
|||
class DocAccessibleChild : public DocAccessibleChildBase
|
||||
{
|
||||
public:
|
||||
explicit DocAccessibleChild(DocAccessible* aDoc);
|
||||
DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager);
|
||||
~DocAccessibleChild();
|
||||
|
||||
virtual void Shutdown() override;
|
||||
|
|
|
@ -361,8 +361,6 @@
|
|||
@RESPATH@/components/PeerConnection.js
|
||||
@RESPATH@/components/PeerConnection.manifest
|
||||
#endif
|
||||
@RESPATH@/components/SiteSpecificUserAgent.js
|
||||
@RESPATH@/components/SiteSpecificUserAgent.manifest
|
||||
@RESPATH@/components/storage-json.js
|
||||
@RESPATH@/components/crypto-SDR.js
|
||||
@RESPATH@/components/Downloads.manifest
|
||||
|
|
|
@ -18,7 +18,7 @@ const TEST_THRESHOLD = {
|
|||
};
|
||||
|
||||
const ADDON_ROLLOUT_POLICY = {
|
||||
"beta": "51alladdons", // Any WebExtension or addon except with mpc = false
|
||||
"beta": "50allmpc",
|
||||
"release": "50allmpc",
|
||||
"esr": "esrA", // WebExtensions and Addons with mpc=true
|
||||
};
|
||||
|
@ -84,7 +84,8 @@ function defineCohort() {
|
|||
let userOptedOut = optedOut();
|
||||
let userOptedIn = optedIn();
|
||||
let disqualified = (Services.appinfo.multiprocessBlockPolicy != 0);
|
||||
let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]);
|
||||
let testThreshold = TEST_THRESHOLD[updateChannel];
|
||||
let testGroup = (getUserSample() < testThreshold);
|
||||
let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
|
||||
let temporaryDisqualification = getTemporaryDisqualification();
|
||||
let temporaryQualification = getTemporaryQualification();
|
||||
|
@ -111,7 +112,11 @@ function defineCohort() {
|
|||
// here will be accumulated as "2 - Disabled", which is fine too.
|
||||
setCohort(`temp-disqualified-${temporaryDisqualification}`);
|
||||
Preferences.reset(PREF_TOGGLE_E10S);
|
||||
} else if (!disqualified && temporaryQualification != "") {
|
||||
} else if (!disqualified && testThreshold < 1.0 &&
|
||||
temporaryQualification != "") {
|
||||
// Users who are qualified for e10s and on channels where some population
|
||||
// would not receive e10s can be pushed into e10s anyway via a temporary
|
||||
// qualification which overrides the user sample value when non-empty.
|
||||
setCohort(`temp-qualified-${temporaryQualification}`);
|
||||
Preferences.set(PREF_TOGGLE_E10S, true);
|
||||
} else if (testGroup) {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>e10srollout@mozilla.org</em:id>
|
||||
<em:version>1.12</em:version>
|
||||
<em:version>1.14</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
|
|
@ -387,8 +387,6 @@
|
|||
@RESPATH@/components/BrowserPageThumbs.manifest
|
||||
@RESPATH@/components/crashmonitor.manifest
|
||||
@RESPATH@/components/nsCrashMonitor.js
|
||||
@RESPATH@/components/SiteSpecificUserAgent.js
|
||||
@RESPATH@/components/SiteSpecificUserAgent.manifest
|
||||
@RESPATH@/components/toolkitsearch.manifest
|
||||
@RESPATH@/components/nsSearchService.js
|
||||
@RESPATH@/components/nsSearchSuggestions.js
|
||||
|
|
|
@ -119,6 +119,7 @@ MACH_MODULES = [
|
|||
'python/mozbuild/mozbuild/frontend/mach_commands.py',
|
||||
'services/common/tests/mach_commands.py',
|
||||
'taskcluster/mach_commands.py',
|
||||
'testing/awsy/mach_commands.py',
|
||||
'testing/firefox-ui/mach_commands.py',
|
||||
'testing/mach_commands.py',
|
||||
'testing/marionette/mach_commands.py',
|
||||
|
|
|
@ -52,7 +52,7 @@ function createSpan(doc) {
|
|||
span.style.display = "inline-block";
|
||||
span.style.width = "100px";
|
||||
span.style.border = "1px solid red";
|
||||
span.style.fontFamily = "monospace";
|
||||
span.style.fontFamily = "Courier New";
|
||||
|
||||
div.style.height = "100%";
|
||||
div.style.position = "absolute";
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "mozilla/dom/WebAuthentication.h"
|
||||
#include "mozilla/dom/workers/RuntimeService.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "nsISiteSpecificUserAgent.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/SSE.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
@ -314,7 +313,6 @@ void
|
|||
Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
nsCOMPtr<nsIURI> codebaseURI;
|
||||
nsCOMPtr<nsPIDOMWindowInner> window;
|
||||
|
||||
if (mWindow) {
|
||||
|
@ -328,15 +326,10 @@ Navigator::GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
|
|||
aUserAgent = customUserAgent;
|
||||
return;
|
||||
}
|
||||
|
||||
nsIDocument* doc = mWindow->GetExtantDoc();
|
||||
if (doc) {
|
||||
doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = GetUserAgent(window, codebaseURI,
|
||||
nsresult rv = GetUserAgent(window,
|
||||
aCallerType == CallerType::System,
|
||||
aUserAgent);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -1885,7 +1878,7 @@ Navigator::ClearUserAgentCache()
|
|||
}
|
||||
|
||||
nsresult
|
||||
Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
|
||||
Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow,
|
||||
bool aIsCallerChrome,
|
||||
nsAString& aUserAgent)
|
||||
{
|
||||
|
@ -1916,19 +1909,30 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
|
|||
|
||||
CopyASCIItoUTF16(ua, aUserAgent);
|
||||
|
||||
if (!aWindow || !aURI) {
|
||||
if (!aWindow) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aWindow->GetDocShell());
|
||||
|
||||
nsCOMPtr<nsISiteSpecificUserAgent> siteSpecificUA =
|
||||
do_GetService("@mozilla.org/dom/site-specific-user-agent;1");
|
||||
if (!siteSpecificUA) {
|
||||
// Copy the User-Agent header from the document channel which has already been
|
||||
// subject to UA overrides.
|
||||
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent);
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel =
|
||||
do_QueryInterface(doc->GetChannel());
|
||||
if (httpChannel) {
|
||||
nsAutoCString userAgent;
|
||||
rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"),
|
||||
userAgent);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
CopyASCIItoUTF16(userAgent, aUserAgent);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
|
|
|
@ -158,7 +158,6 @@ public:
|
|||
bool aUsePrefOverriddenValue);
|
||||
|
||||
static nsresult GetUserAgent(nsPIDOMWindowInner* aWindow,
|
||||
nsIURI* aURI,
|
||||
bool aIsCallerChrome,
|
||||
nsAString& aUserAgent);
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const MAX_CACHE_SIZE = 250;
|
||||
const PREF_UPDATE = "general.useragent.updates.";
|
||||
const PREF_OVERRIDE = "general.useragent.override.";
|
||||
const XPCOM_SHUTDOWN = "xpcom-shutdown";
|
||||
const HTTP_PROTO_HANDLER = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
function SiteSpecificUserAgent() {
|
||||
this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
if (this.inParent) {
|
||||
Cu.import("resource://gre/modules/UserAgentOverrides.jsm");
|
||||
} else {
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Services.prefs.addObserver(PREF_OVERRIDE, this, false);
|
||||
Services.prefs.addObserver(PREF_UPDATE, this, false);
|
||||
Services.obs.addObserver(this, XPCOM_SHUTDOWN, false);
|
||||
this.userAgentCache = new Map;
|
||||
}
|
||||
}
|
||||
|
||||
SiteSpecificUserAgent.prototype = {
|
||||
getUserAgentForURIAndWindow: function ssua_getUserAgentForURIAndWindow(aURI, aWindow) {
|
||||
if (this.inParent) {
|
||||
return UserAgentOverrides.getOverrideForURI(aURI) || HTTP_PROTO_HANDLER.userAgent;
|
||||
}
|
||||
|
||||
let host = aURI.asciiHost;
|
||||
let cachedResult = this.userAgentCache.get(host);
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
let data = { uri: aURI.spec };
|
||||
let result = cpmm.sendRpcMessage("Useragent:GetOverride", data)[0] || HTTP_PROTO_HANDLER.userAgent;
|
||||
|
||||
if (this.userAgentCache.size >= MAX_CACHE_SIZE) {
|
||||
this.userAgentCache.clear();
|
||||
}
|
||||
|
||||
this.userAgentCache.set(host, result);
|
||||
return result;
|
||||
},
|
||||
|
||||
invalidateCache: function() {
|
||||
this.userAgentCache.clear();
|
||||
},
|
||||
|
||||
clean: function() {
|
||||
this.userAgentCache.clear();
|
||||
if (!this.inParent) {
|
||||
Services.obs.removeObserver(this, XPCOM_SHUTDOWN);
|
||||
Services.prefs.removeObserver(PREF_OVERRIDE, this);
|
||||
Services.prefs.removeObserver(PREF_UPDATE, this);
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
this.invalidateCache();
|
||||
break;
|
||||
case XPCOM_SHUTDOWN:
|
||||
this.clean();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
classID: Components.ID("{506c680f-3d1c-4954-b351-2c80afbc37d3}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISiteSpecificUserAgent])
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SiteSpecificUserAgent]);
|
|
@ -1,2 +0,0 @@
|
|||
component {506c680f-3d1c-4954-b351-2c80afbc37d3} SiteSpecificUserAgent.js
|
||||
contract @mozilla.org/dom/site-specific-user-agent;1 {506c680f-3d1c-4954-b351-2c80afbc37d3}
|
|
@ -308,6 +308,7 @@ StructuredCloneHolder::Read(nsISupports* aParent,
|
|||
// If we are tranferring something, we cannot call 'Read()' more than once.
|
||||
if (mSupportsTransferring) {
|
||||
mBlobImplArray.Clear();
|
||||
mWasmModuleArray.Clear();
|
||||
mClonedSurfaces.Clear();
|
||||
Clear();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ XPIDL_SOURCES += [
|
|||
'nsISelectionListener.idl',
|
||||
'nsISelectionPrivate.idl',
|
||||
'nsISimpleContentPolicy.idl',
|
||||
'nsISiteSpecificUserAgent.idl',
|
||||
'nsISlowScriptDebug.idl',
|
||||
]
|
||||
|
||||
|
@ -418,13 +417,6 @@ EXTRA_COMPONENTS += [
|
|||
'SlowScriptDebug.manifest',
|
||||
]
|
||||
|
||||
# Firefox for Android provides an alternate version of this component
|
||||
if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
|
||||
EXTRA_COMPONENTS += [
|
||||
'SiteSpecificUserAgent.js',
|
||||
'SiteSpecificUserAgent.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DOMRequestHelper.jsm',
|
||||
'IndexedDBHelper.jsm',
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface mozIDOMWindow;
|
||||
|
||||
/**
|
||||
* nsISiteSpecificUserAgent provides you with site/window-specific User Agent strings.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(0f0ace30-9ab1-4175-9d60-fd26c0324adc)]
|
||||
interface nsISiteSpecificUserAgent : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get the User Agent string for a given URI.
|
||||
*
|
||||
* @param aURI is the URI of the page the UA string is used for.
|
||||
*
|
||||
* @param aWindow is the window this UA is being requested for
|
||||
*
|
||||
* @returns the User Agent string for the given URI. If no override applies,
|
||||
* the default User Agent string is used.
|
||||
*/
|
||||
AString getUserAgentForURIAndWindow(in nsIURI aURI, in mozIDOMWindow aWindow);
|
||||
};
|
|
@ -9,7 +9,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="scrollable" style="font-family:monospace; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
|
||||
<div id="scrollable" style="font-family:'Courier New'; font-size: 18px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
|
||||
<div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
|
||||
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
|
||||
Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
|
||||
|
@ -44,6 +44,7 @@
|
|||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(runTests, window);
|
||||
|
|
|
@ -7,71 +7,27 @@
|
|||
#include "MemoryBlobImpl.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// XXXkhuey the input stream that we pass out of a File
|
||||
// can outlive the actual File object. Thus, we must
|
||||
// ensure that the buffer underlying the stream we get
|
||||
// from NS_NewByteInputStream is held alive as long as the
|
||||
// stream is. We do that by passing back this class instead.
|
||||
class DataOwnerAdapter final : public nsIInputStream,
|
||||
public nsISeekableStream,
|
||||
public nsIIPCSerializableInputStream
|
||||
{
|
||||
typedef MemoryBlobImpl::DataOwner DataOwner;
|
||||
public:
|
||||
static nsresult Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
nsIInputStream** _retval);
|
||||
NS_IMPL_ADDREF(MemoryBlobImpl::DataOwnerAdapter)
|
||||
NS_IMPL_RELEASE(MemoryBlobImpl::DataOwnerAdapter)
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
// These are mandatory.
|
||||
NS_FORWARD_NSIINPUTSTREAM(mStream->)
|
||||
NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
|
||||
|
||||
// This is optional. We use a conditional QI to keep it from being called
|
||||
// if the underlying stream doesn't support it.
|
||||
NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
|
||||
|
||||
private:
|
||||
~DataOwnerAdapter() {}
|
||||
|
||||
DataOwnerAdapter(DataOwner* aDataOwner,
|
||||
nsIInputStream* aStream)
|
||||
: mDataOwner(aDataOwner), mStream(aStream),
|
||||
mSeekableStream(do_QueryInterface(aStream)),
|
||||
mSerializableInputStream(do_QueryInterface(aStream))
|
||||
{
|
||||
MOZ_ASSERT(mSeekableStream, "Somebody gave us the wrong stream!");
|
||||
}
|
||||
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(DataOwnerAdapter)
|
||||
NS_IMPL_RELEASE(DataOwnerAdapter)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
|
||||
NS_INTERFACE_MAP_BEGIN(MemoryBlobImpl::DataOwnerAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
|
||||
mSerializableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
nsIInputStream** _retval)
|
||||
nsresult MemoryBlobImpl::DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
nsIInputStream** _retval)
|
||||
{
|
||||
nsresult rv;
|
||||
MOZ_ASSERT(aDataOwner, "Uh ...");
|
||||
|
@ -85,7 +41,8 @@ nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
|||
NS_ASSIGNMENT_DEPEND);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
|
||||
NS_ADDREF(*_retval =
|
||||
new MemoryBlobImpl::DataOwnerAdapter(aDataOwner, stream));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -110,7 +67,8 @@ MemoryBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
aRv = DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
|
||||
aRv = MemoryBlobImpl::DataOwnerAdapter::Create(mDataOwner, mStart, mLength,
|
||||
aStream);
|
||||
}
|
||||
|
||||
/* static */ StaticMutex
|
||||
|
|
|
@ -11,7 +11,11 @@
|
|||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsICloneableInputStream.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -94,6 +98,50 @@ public:
|
|||
uint64_t mLength;
|
||||
};
|
||||
|
||||
class DataOwnerAdapter final : public nsIInputStream
|
||||
, public nsISeekableStream
|
||||
, public nsIIPCSerializableInputStream
|
||||
, public nsICloneableInputStream
|
||||
{
|
||||
typedef MemoryBlobImpl::DataOwner DataOwner;
|
||||
public:
|
||||
static nsresult Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
nsIInputStream** _retval);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
// These are mandatory.
|
||||
NS_FORWARD_NSIINPUTSTREAM(mStream->)
|
||||
NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
|
||||
NS_FORWARD_NSICLONEABLEINPUTSTREAM(mCloneableInputStream->)
|
||||
|
||||
// This is optional. We use a conditional QI to keep it from being called
|
||||
// if the underlying stream doesn't support it.
|
||||
NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
|
||||
|
||||
private:
|
||||
~DataOwnerAdapter() {}
|
||||
|
||||
DataOwnerAdapter(DataOwner* aDataOwner,
|
||||
nsIInputStream* aStream)
|
||||
: mDataOwner(aDataOwner)
|
||||
, mStream(aStream)
|
||||
, mSeekableStream(do_QueryInterface(aStream))
|
||||
, mSerializableInputStream(do_QueryInterface(aStream))
|
||||
, mCloneableInputStream(do_QueryInterface(aStream))
|
||||
{
|
||||
MOZ_ASSERT(mSeekableStream, "Somebody gave us the wrong stream!");
|
||||
}
|
||||
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
|
||||
nsCOMPtr<nsICloneableInputStream> mCloneableInputStream;
|
||||
};
|
||||
|
||||
private:
|
||||
// Create slice
|
||||
MemoryBlobImpl(const MemoryBlobImpl* aOther, uint64_t aStart,
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "mozilla/dom/PBlobStreamChild.h"
|
||||
#include "mozilla/dom/PBlobStreamParent.h"
|
||||
#include "mozilla/dom/indexedDB/FileSnapshot.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamChild.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamParent.h"
|
||||
#include "mozilla/dom/IndexedDatabaseManager.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
|
@ -617,6 +619,108 @@ struct MOZ_STACK_CLASS CreateBlobImplMetadata final
|
|||
}
|
||||
};
|
||||
|
||||
template<class M>
|
||||
PMemoryStreamChild*
|
||||
SerializeInputStreamInChunks(nsIInputStream* aInputStream, uint64_t aLength,
|
||||
M* aManager)
|
||||
{
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
PMemoryStreamChild* child = aManager->SendPMemoryStreamConstructor(aLength);
|
||||
MOZ_ASSERT(child);
|
||||
|
||||
const uint64_t kMaxChunk = 1024 * 1024;
|
||||
|
||||
while (aLength) {
|
||||
FallibleTArray<uint8_t> buffer;
|
||||
|
||||
uint64_t size = XPCOM_MIN(aLength, kMaxChunk);
|
||||
if (NS_WARN_IF(!buffer.SetLength(size, fallible))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t read;
|
||||
nsresult rv = aInputStream->Read(reinterpret_cast<char*>(buffer.Elements()),
|
||||
size, &read);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(read == 0)) {
|
||||
// We were not expecting a read==0 here.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(read <= size);
|
||||
aLength -= read;
|
||||
|
||||
if (NS_WARN_IF(!buffer.SetLength(read, fallible))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
child->SendAddChunk(buffer);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
void
|
||||
DeleteStreamMemoryFromBlobDataStream(BlobDataStream& aStream)
|
||||
{
|
||||
PMemoryStreamChild* actor = aStream.streamChild();
|
||||
if (actor) {
|
||||
actor->Send__delete__(actor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeleteStreamMemoryFromBlobData(BlobData& aBlobData)
|
||||
{
|
||||
switch (aBlobData.type()) {
|
||||
case BlobData::TBlobDataStream:
|
||||
DeleteStreamMemoryFromBlobDataStream(aBlobData.get_BlobDataStream());
|
||||
return;
|
||||
|
||||
case BlobData::TArrayOfBlobData: {
|
||||
nsTArray<BlobData>& arrayBlobData = aBlobData.get_ArrayOfBlobData();
|
||||
for (uint32_t i = 0; i < arrayBlobData.Length(); ++i) {
|
||||
DeleteStreamMemoryFromBlobData(arrayBlobData[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
// Nothing to do here.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeleteStreamMemoryFromOptionalBlobData(OptionalBlobData& aParams)
|
||||
{
|
||||
if (aParams.type() == OptionalBlobData::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteStreamMemoryFromBlobData(aParams.get_BlobData());
|
||||
}
|
||||
|
||||
void
|
||||
DeleteStreamMemory(AnyBlobConstructorParams& aParams)
|
||||
{
|
||||
if (aParams.type() == AnyBlobConstructorParams::TFileBlobConstructorParams) {
|
||||
FileBlobConstructorParams& fileParams = aParams.get_FileBlobConstructorParams();
|
||||
DeleteStreamMemoryFromOptionalBlobData(fileParams.optionalBlobData());
|
||||
return;
|
||||
}
|
||||
|
||||
if (aParams.type() == AnyBlobConstructorParams::TNormalBlobConstructorParams) {
|
||||
NormalBlobConstructorParams& normalParams = aParams.get_NormalBlobConstructorParams();
|
||||
DeleteStreamMemoryFromOptionalBlobData(normalParams.optionalBlobData());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
|
@ -645,7 +749,11 @@ CreateBlobImpl(const BlobDataStream& aStream,
|
|||
{
|
||||
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream = DeserializeIPCStream(aStream.stream());
|
||||
MemoryStreamParent* actor =
|
||||
static_cast<MemoryStreamParent*>(aStream.streamParent());
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
actor->GetStream(getter_AddRefs(inputStream));
|
||||
if (!inputStream) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return nullptr;
|
||||
|
@ -837,10 +945,9 @@ CreateBlobImpl(const ParentBlobConstructorParams& aParams,
|
|||
}
|
||||
|
||||
template <class ChildManagerType>
|
||||
void
|
||||
bool
|
||||
BlobDataFromBlobImpl(ChildManagerType* aManager, BlobImpl* aBlobImpl,
|
||||
BlobData& aBlobData,
|
||||
nsTArray<UniquePtr<AutoIPCStream>>& aIPCStreams)
|
||||
BlobData& aBlobData)
|
||||
{
|
||||
MOZ_ASSERT(gProcessType != GeckoProcessType_Default);
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
|
@ -858,11 +965,13 @@ BlobDataFromBlobImpl(ChildManagerType* aManager, BlobImpl* aBlobImpl,
|
|||
for (uint32_t count = subBlobs->Length(), index = 0;
|
||||
index < count;
|
||||
index++) {
|
||||
BlobDataFromBlobImpl(aManager, subBlobs->ElementAt(index),
|
||||
subBlobDatas[index], aIPCStreams);
|
||||
if (!BlobDataFromBlobImpl(aManager, subBlobs->ElementAt(index),
|
||||
subBlobDatas[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlobImpl);
|
||||
|
@ -871,7 +980,7 @@ BlobDataFromBlobImpl(ChildManagerType* aManager, BlobImpl* aBlobImpl,
|
|||
MOZ_ASSERT(actor);
|
||||
|
||||
aBlobData = actor->ParentID();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
|
@ -882,11 +991,14 @@ BlobDataFromBlobImpl(ChildManagerType* aManager, BlobImpl* aBlobImpl,
|
|||
aBlobImpl->GetInternalStream(getter_AddRefs(inputStream), rv);
|
||||
MOZ_ALWAYS_TRUE(!rv.Failed());
|
||||
|
||||
UniquePtr<AutoIPCStream> autoStream(new AutoIPCStream());
|
||||
autoStream->Serialize(inputStream, aManager);
|
||||
aBlobData = BlobDataStream(autoStream->TakeValue(), length);
|
||||
PMemoryStreamChild* streamActor =
|
||||
SerializeInputStreamInChunks(inputStream, length, aManager);
|
||||
if (!streamActor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aIPCStreams.AppendElement(Move(autoStream));
|
||||
aBlobData = BlobDataStream(nullptr, streamActor, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
RemoteInputStream::RemoteInputStream(BlobImpl* aBlobImpl,
|
||||
|
@ -3477,7 +3589,6 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
|
|||
MOZ_ASSERT(!aBlobImpl->IsDateUnknown());
|
||||
|
||||
AnyBlobConstructorParams blobParams;
|
||||
nsTArray<UniquePtr<AutoIPCStream>> autoIPCStreams;
|
||||
|
||||
if (gProcessType == GeckoProcessType_Default) {
|
||||
RefPtr<BlobImpl> sameProcessImpl = aBlobImpl;
|
||||
|
@ -3489,7 +3600,9 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
|
|||
// BlobData is going to be populate here and it _must_ be send via IPC in
|
||||
// order to avoid leaks.
|
||||
BlobData blobData;
|
||||
BlobDataFromBlobImpl(aManager, aBlobImpl, blobData, autoIPCStreams);
|
||||
if (NS_WARN_IF(!BlobDataFromBlobImpl(aManager, aBlobImpl, blobData))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsString contentType;
|
||||
aBlobImpl->GetType(contentType);
|
||||
|
@ -3524,7 +3637,8 @@ BlobChild::GetOrCreateFromImpl(ChildManagerType* aManager,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
autoIPCStreams.Clear();
|
||||
DeleteStreamMemory(params.blobParams());
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ipc_MemoryStreamChild_h
|
||||
#define mozilla_dom_ipc_MemoryStreamChild_h
|
||||
|
||||
#include "mozilla/ipc/PMemoryStreamChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MemoryStreamChild final : public mozilla::ipc::PMemoryStreamChild
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ipc_MemoryStreamChild_h
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MemoryStreamParent.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
MemoryStreamParent::MemoryStreamParent(uint64_t aSize)
|
||||
: mSize(aSize)
|
||||
, mCurSize(0)
|
||||
{}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
MemoryStreamParent::RecvAddChunk(nsTArray<unsigned char>&& aData)
|
||||
{
|
||||
MOZ_ASSERT(mSize);
|
||||
|
||||
uint64_t dataLength = aData.Length();
|
||||
|
||||
if (!dataLength || mSize < (mCurSize + dataLength)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
void* buffer = malloc(dataLength);
|
||||
if (NS_WARN_IF(!buffer)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
memcpy(buffer, aData.Elements(), dataLength);
|
||||
mData.AppendElement(new MemoryBlobImpl::DataOwner(buffer, dataLength));
|
||||
|
||||
mCurSize += dataLength;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
MemoryStreamParent::ActorDestroy(IProtocol::ActorDestroyReason)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MemoryStreamParent::GetStream(nsIInputStream** aInputStream)
|
||||
{
|
||||
if (mCurSize != mSize) {
|
||||
*aInputStream = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMultiplexInputStream> stream =
|
||||
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
||||
if (NS_WARN_IF(!stream)) {
|
||||
*aInputStream = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mData.Length(); ++i) {
|
||||
nsCOMPtr<nsIInputStream> dataStream;
|
||||
nsresult rv =
|
||||
MemoryBlobImpl::DataOwnerAdapter::Create(mData[i], 0, mData[i]->mLength,
|
||||
getter_AddRefs(dataStream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
*aInputStream = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
stream->AppendStream(dataStream);
|
||||
}
|
||||
|
||||
stream.forget(aInputStream);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ipc_MemoryStreamParent_h
|
||||
#define mozilla_dom_ipc_MemoryStreamParent_h
|
||||
|
||||
#include "mozilla/ipc/PMemoryStreamParent.h"
|
||||
#include "mozilla/dom/MemoryBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MemoryStreamParent final : public mozilla::ipc::PMemoryStreamParent
|
||||
{
|
||||
public:
|
||||
explicit MemoryStreamParent(uint64_t aSize);
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvAddChunk(nsTArray<unsigned char>&& aData) override;
|
||||
|
||||
void
|
||||
ActorDestroy(IProtocol::ActorDestroyReason) override;
|
||||
|
||||
void
|
||||
GetStream(nsIInputStream** aInputStream);
|
||||
|
||||
private:
|
||||
uint64_t mSize;
|
||||
uint64_t mCurSize;
|
||||
|
||||
nsTArray<RefPtr<MemoryBlobImpl::DataOwner>> mData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ipc_MemoryStreamParent_h
|
|
@ -9,6 +9,7 @@ include protocol PContentBridge;
|
|||
include protocol PFileDescriptorSet;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include protocol PMemoryStream;
|
||||
|
||||
include BlobTypes;
|
||||
include DOMTypes;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
protocol PMemoryStream
|
||||
{
|
||||
manager PBackground or PContent or PContentBridge;
|
||||
|
||||
parent:
|
||||
async AddChunk(uint8_t[] data);
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -7,17 +7,21 @@
|
|||
EXPORTS.mozilla.dom.ipc += [
|
||||
'BlobChild.h',
|
||||
'BlobParent.h',
|
||||
'MemoryStreamChild.h',
|
||||
'MemoryStreamParent.h',
|
||||
'nsIRemoteBlob.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'Blob.cpp',
|
||||
'MemoryStreamParent.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'BlobTypes.ipdlh',
|
||||
'PBlob.ipdl',
|
||||
'PBlobStream.ipdl',
|
||||
'PMemoryStream.ipdl',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
|
@ -68,6 +68,12 @@ ContentBridgeChild::SendPBlobConstructor(PBlobChild* actor,
|
|||
return PContentBridgeChild::SendPBlobConstructor(actor, params);
|
||||
}
|
||||
|
||||
PMemoryStreamChild*
|
||||
ContentBridgeChild::SendPMemoryStreamConstructor(const uint64_t& aSize)
|
||||
{
|
||||
return PContentBridgeChild::SendPMemoryStreamConstructor(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
|
||||
const TabId& aTabId,
|
||||
|
@ -168,6 +174,18 @@ ContentBridgeChild::DeallocPBlobChild(PBlobChild* aActor)
|
|||
return nsIContentChild::DeallocPBlobChild(aActor);
|
||||
}
|
||||
|
||||
PMemoryStreamChild*
|
||||
ContentBridgeChild::AllocPMemoryStreamChild(const uint64_t& aSize)
|
||||
{
|
||||
return nsIContentChild::AllocPMemoryStreamChild(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeChild::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
|
||||
{
|
||||
return nsIContentChild::DeallocPMemoryStreamChild(aActor);
|
||||
}
|
||||
|
||||
PChildToParentStreamChild*
|
||||
ContentBridgeChild::AllocPChildToParentStreamChild()
|
||||
{
|
||||
|
|
|
@ -36,6 +36,9 @@ public:
|
|||
SendPBlobConstructor(PBlobChild* actor,
|
||||
const BlobConstructorParams& aParams) override;
|
||||
|
||||
virtual PMemoryStreamChild*
|
||||
SendPMemoryStreamConstructor(const uint64_t& aSize) override;
|
||||
|
||||
jsipc::CPOWManager* GetCPOWManager() override;
|
||||
|
||||
virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
|
||||
|
@ -82,6 +85,10 @@ protected:
|
|||
virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams) override;
|
||||
virtual bool DeallocPBlobChild(PBlobChild*) override;
|
||||
|
||||
virtual PMemoryStreamChild*
|
||||
AllocPMemoryStreamChild(const uint64_t& aSize) override;
|
||||
virtual bool DeallocPMemoryStreamChild(PMemoryStreamChild*) override;
|
||||
|
||||
virtual mozilla::ipc::PChildToParentStreamChild*
|
||||
AllocPChildToParentStreamChild() override;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/ContentBridgeParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamParent.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "base/task.h"
|
||||
|
@ -128,6 +129,18 @@ ContentBridgeParent::DeallocPBlobParent(PBlobParent* aActor)
|
|||
return nsIContentParent::DeallocPBlobParent(aActor);
|
||||
}
|
||||
|
||||
PMemoryStreamParent*
|
||||
ContentBridgeParent::AllocPMemoryStreamParent(const uint64_t& aSize)
|
||||
{
|
||||
return nsIContentParent::AllocPMemoryStreamParent(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentBridgeParent::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
|
||||
{
|
||||
return nsIContentParent::DeallocPMemoryStreamParent(aActor);
|
||||
}
|
||||
|
||||
mozilla::jsipc::PJavaScriptParent *
|
||||
ContentBridgeParent::AllocPJavaScriptParent()
|
||||
{
|
||||
|
|
|
@ -136,6 +136,11 @@ protected:
|
|||
|
||||
virtual bool DeallocPBlobParent(PBlobParent*) override;
|
||||
|
||||
virtual PMemoryStreamParent*
|
||||
AllocPMemoryStreamParent(const uint64_t& aSize) override;
|
||||
|
||||
virtual bool DeallocPMemoryStreamParent(PMemoryStreamParent*) override;
|
||||
|
||||
virtual PChildToParentStreamParent* AllocPChildToParentStreamParent() override;
|
||||
|
||||
virtual bool
|
||||
|
|
|
@ -1524,6 +1524,18 @@ ContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
|
|||
return nsIContentChild::DeallocPBrowserChild(aIframe);
|
||||
}
|
||||
|
||||
PMemoryStreamChild*
|
||||
ContentChild::AllocPMemoryStreamChild(const uint64_t& aSize)
|
||||
{
|
||||
return nsIContentChild::AllocPMemoryStreamChild(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
|
||||
{
|
||||
return nsIContentChild::DeallocPMemoryStreamChild(aActor);
|
||||
}
|
||||
|
||||
PBlobChild*
|
||||
ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
|
||||
{
|
||||
|
@ -1561,6 +1573,16 @@ ContentChild::SendPBlobConstructor(PBlobChild* aActor,
|
|||
return PContentChild::SendPBlobConstructor(aActor, aParams);
|
||||
}
|
||||
|
||||
PMemoryStreamChild*
|
||||
ContentChild::SendPMemoryStreamConstructor(const uint64_t& aSize)
|
||||
{
|
||||
if (IsShuttingDown()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return PContentChild::SendPMemoryStreamConstructor(aSize);
|
||||
}
|
||||
|
||||
PPresentationChild*
|
||||
ContentChild::AllocPPresentationChild()
|
||||
{
|
||||
|
|
|
@ -182,6 +182,12 @@ public:
|
|||
|
||||
virtual bool DeallocPBlobChild(PBlobChild* aActor) override;
|
||||
|
||||
virtual PMemoryStreamChild*
|
||||
AllocPMemoryStreamChild(const uint64_t& aSize) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPMemoryStreamChild(PMemoryStreamChild* aActor) override;
|
||||
|
||||
virtual PHalChild* AllocPHalChild() override;
|
||||
virtual bool DeallocPHalChild(PHalChild*) override;
|
||||
|
||||
|
@ -489,6 +495,9 @@ public:
|
|||
SendPBlobConstructor(PBlobChild* actor,
|
||||
const BlobConstructorParams& params) override;
|
||||
|
||||
virtual PMemoryStreamChild*
|
||||
SendPMemoryStreamConstructor(const uint64_t& aSize) override;
|
||||
|
||||
virtual PFileDescriptorSetChild*
|
||||
SendPFileDescriptorSetConstructor(const FileDescriptor&) override;
|
||||
|
||||
|
|
|
@ -2820,6 +2820,18 @@ ContentParent::DeallocPBlobParent(PBlobParent* aActor)
|
|||
return nsIContentParent::DeallocPBlobParent(aActor);
|
||||
}
|
||||
|
||||
PMemoryStreamParent*
|
||||
ContentParent::AllocPMemoryStreamParent(const uint64_t& aSize)
|
||||
{
|
||||
return nsIContentParent::AllocPMemoryStreamParent(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
|
||||
{
|
||||
return nsIContentParent::DeallocPMemoryStreamParent(aActor);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& aParams)
|
||||
|
|
|
@ -825,6 +825,11 @@ private:
|
|||
|
||||
virtual bool DeallocPBlobParent(PBlobParent* aActor) override;
|
||||
|
||||
virtual PMemoryStreamParent*
|
||||
AllocPMemoryStreamParent(const uint64_t& aSize) override;
|
||||
|
||||
virtual bool DeallocPMemoryStreamParent(PMemoryStreamParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& params) override;
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBlob;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PParentToChildStream;
|
||||
include IPCStream;
|
||||
include protocol PMemoryStream;
|
||||
include ProtocolTypes;
|
||||
|
||||
using struct mozilla::void_t
|
||||
|
@ -47,7 +45,7 @@ struct ClonedMessageData
|
|||
|
||||
struct BlobDataStream
|
||||
{
|
||||
IPCStream stream;
|
||||
PMemoryStream stream;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ include protocol PHeapSnapshotTempFileHelper;
|
|||
include protocol PProcessHangMonitor;
|
||||
include protocol PImageBridge;
|
||||
include protocol PMedia;
|
||||
include protocol PMemoryStream;
|
||||
include protocol PNecko;
|
||||
include protocol PGMPContent;
|
||||
include protocol PGMPService;
|
||||
|
@ -283,6 +284,7 @@ nested(upto inside_cpow) sync protocol PContent
|
|||
manages PHandlerService;
|
||||
manages PHeapSnapshotTempFileHelper;
|
||||
manages PMedia;
|
||||
manages PMemoryStream;
|
||||
manages PNecko;
|
||||
manages POfflineCacheUpdate;
|
||||
manages PPrinting;
|
||||
|
@ -647,6 +649,8 @@ parent:
|
|||
|
||||
async PRemoteSpellcheckEngine();
|
||||
|
||||
async PMemoryStream(uint64_t aSize);
|
||||
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId tid);
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ include protocol PContent;
|
|||
include protocol PJavaScript;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PChildToParentStream;
|
||||
include protocol PMemoryStream;
|
||||
include protocol PParentToChildStream;
|
||||
|
||||
include DOMTypes;
|
||||
|
@ -40,6 +41,7 @@ nested(upto inside_cpow) sync protocol PContentBridge
|
|||
manages PFileDescriptorSet;
|
||||
manages PJavaScript;
|
||||
manages PChildToParentStream;
|
||||
manages PMemoryStream;
|
||||
manages PParentToChildStream;
|
||||
|
||||
child:
|
||||
|
@ -64,6 +66,8 @@ parent:
|
|||
|
||||
async PChildToParentStream();
|
||||
|
||||
async PMemoryStream(uint64_t aSize);
|
||||
|
||||
both:
|
||||
// Both the parent and the child can construct the PBrowser.
|
||||
// See the comment in PContent::PBrowser().
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/ipc/IPCStreamSource.h"
|
||||
#include "mozilla/ipc/PChildToParentStreamChild.h"
|
||||
#include "mozilla/ipc/PParentToChildStreamChild.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamChild.h"
|
||||
|
||||
#include "nsPrintfCString.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -102,6 +103,19 @@ nsIContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PMemoryStreamChild*
|
||||
nsIContentChild::AllocPMemoryStreamChild(const uint64_t& aSize)
|
||||
{
|
||||
return new MemoryStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContentChild::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PBlobChild*
|
||||
nsIContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
|
||||
{
|
||||
|
|
|
@ -64,6 +64,9 @@ public:
|
|||
SendPBlobConstructor(PBlobChild* aActor,
|
||||
const BlobConstructorParams& aParams) = 0;
|
||||
|
||||
virtual mozilla::ipc::PMemoryStreamChild*
|
||||
SendPMemoryStreamConstructor(const uint64_t& aSize) = 0;
|
||||
|
||||
virtual bool
|
||||
SendPBrowserConstructor(PBrowserChild* aActor,
|
||||
const TabId& aTabId,
|
||||
|
@ -100,6 +103,11 @@ protected:
|
|||
|
||||
virtual bool DeallocPBlobChild(PBlobChild* aActor);
|
||||
|
||||
virtual mozilla::ipc::PMemoryStreamChild*
|
||||
AllocPMemoryStreamChild(const uint64_t& aSize);
|
||||
|
||||
virtual bool DeallocPMemoryStreamChild(mozilla::ipc::PMemoryStreamChild* aActor);
|
||||
|
||||
virtual mozilla::ipc::PChildToParentStreamChild* AllocPChildToParentStreamChild();
|
||||
|
||||
virtual bool
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamParent.h"
|
||||
#include "mozilla/dom/ipc/StructuredCloneData.h"
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
|
@ -187,6 +188,19 @@ nsIContentParent::DeallocPBlobParent(PBlobParent* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PMemoryStreamParent*
|
||||
nsIContentParent::AllocPMemoryStreamParent(const uint64_t& aSize)
|
||||
{
|
||||
return new MemoryStreamParent(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
nsIContentParent::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
BlobParent*
|
||||
nsIContentParent::GetOrCreateActorForBlob(Blob* aBlob)
|
||||
{
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace ipc {
|
|||
class PFileDescriptorSetParent;
|
||||
class PChildToParentStreamParent;
|
||||
class PParentToChildStreamParent;
|
||||
class PMemoryStreamParent;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
@ -121,6 +122,11 @@ protected: // IPDL methods
|
|||
|
||||
virtual bool DeallocPBlobParent(PBlobParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::PMemoryStreamParent*
|
||||
AllocPMemoryStreamParent(const uint64_t& aSize);
|
||||
|
||||
virtual bool DeallocPMemoryStreamParent(mozilla::ipc::PMemoryStreamParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::PFileDescriptorSetParent*
|
||||
AllocPFileDescriptorSetParent(const mozilla::ipc::FileDescriptor& aFD);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
left: 0em;
|
||||
top: 0em;
|
||||
font-size: 10pt;
|
||||
font-family: monospace;
|
||||
font-family: 'Courier New';
|
||||
line-height: 20px;
|
||||
letter-spacing: 0px;
|
||||
margin-top:-1px; /* nix the text area border */
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
|
||||
<script type="application/javascript">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
var SimpleTest = window.opener.SimpleTest;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
|
@ -127,13 +129,7 @@
|
|||
targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
setEnd(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
|
||||
if (isLinux || isMac) {
|
||||
// XXX I think this is a bug, the right hand selection is 4.5 characters over with a
|
||||
// monspaced font. what we want: t(te)s(ts)election1 what we get: t(te)st(se)lection1
|
||||
checkSelection(document, "split selection", "tese");
|
||||
} else if (isWindows) {
|
||||
checkSelection(document, "split selection", "tets");
|
||||
}
|
||||
|
||||
// Trying to select where there's no text, should fail but not throw
|
||||
let result = dwu.selectAtPoint(rect.left - 20, rect.top - 20, Ci.nsIDOMWindowUtils.SELECT_CHARACTER, false);
|
||||
|
@ -228,7 +224,7 @@
|
|||
<style type="text/css">
|
||||
|
||||
body {
|
||||
font-family: monospace;
|
||||
font-family: 'Courier New';
|
||||
margin-left: 40px;
|
||||
margin-top: 40px;
|
||||
padding: 0;
|
||||
|
@ -267,7 +263,7 @@ body {
|
|||
|
||||
<br />
|
||||
|
||||
<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
|
||||
<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: \'Courier New\';' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
|
||||
|
||||
<br/>
|
||||
|
||||
|
|
|
@ -1120,6 +1120,8 @@ NS_IMETHODIMP nsWebBrowserPersist::OnStatus(
|
|||
case NS_NET_STATUS_END_FTP_TRANSACTION:
|
||||
case NS_NET_STATUS_CONNECTING_TO:
|
||||
case NS_NET_STATUS_CONNECTED_TO:
|
||||
case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
|
||||
case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
|
||||
case NS_NET_STATUS_SENDING_TO:
|
||||
case NS_NET_STATUS_RECEIVING_FROM:
|
||||
case NS_NET_STATUS_WAITING_FOR:
|
||||
|
|
|
@ -138,17 +138,9 @@ public:
|
|||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = mWorkerPrivate->GetWindow();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (window && window->GetDocShell()) {
|
||||
nsIDocument* doc = window->GetExtantDoc();
|
||||
if (doc) {
|
||||
doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
|
||||
}
|
||||
}
|
||||
|
||||
bool isCallerChrome = mWorkerPrivate->UsesSystemPrincipal();
|
||||
nsresult rv = dom::Navigator::GetUserAgent(window, uri,
|
||||
isCallerChrome, mUA);
|
||||
nsresult rv = dom::Navigator::GetUserAgent(window, isCallerChrome, mUA);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to retrieve user-agent from the worker thread.");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
let { classes: Cc, interfaces: Ci } = Components;
|
||||
|
||||
add_task(function* test() {
|
||||
yield SpecialPowers.pushPrefEnv(
|
||||
{set: [["browser.tabs.remote.separateFileUriProcess", true]]}
|
||||
);
|
||||
|
||||
let file = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
|
|
|
@ -485,6 +485,7 @@ private:
|
|||
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.background-image", LayersAllowBackgroundImage, false);
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.border-layers", LayersAllowBorderLayers, false);
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, gfxPrefs::OverrideBase_WebRender());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, false);
|
||||
|
|
|
@ -162,6 +162,61 @@ static inline WrColor ToWrColor(const gfx::Color& color)
|
|||
return c;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrPoint ToWrPoint(const gfx::PointTyped<T>& point)
|
||||
{
|
||||
WrPoint p;
|
||||
p.x = point.x;
|
||||
p.y = point.y;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrPoint ToWrPoint(const gfx::IntPointTyped<T>& point)
|
||||
{
|
||||
return ToWrPoint(IntPointToPoint(point));
|
||||
}
|
||||
|
||||
static inline WrPoint ToWrPoint(const gfx::Point& point)
|
||||
{
|
||||
WrPoint p;
|
||||
p.x = point.x;
|
||||
p.y = point.y;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrRect ToWrRect(const gfx::RectTyped<T>& rect)
|
||||
{
|
||||
WrRect r;
|
||||
r.x = rect.x;
|
||||
r.y = rect.y;
|
||||
r.width = rect.width;
|
||||
r.height = rect.height;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
|
||||
{
|
||||
return ToWrRect(IntRectToRect(rect));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrSize ToWrSize(const gfx::SizeTyped<T>& size)
|
||||
{
|
||||
WrSize ls;
|
||||
ls.width = size.width;
|
||||
ls.height = size.height;
|
||||
return ls;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrSize ToWrSize(const gfx::IntSizeTyped<T>& size)
|
||||
{
|
||||
return ToWrSize(IntSizeToSize(size));
|
||||
}
|
||||
|
||||
static inline WrBorderStyle ToWrBorderStyle(const uint8_t& style)
|
||||
{
|
||||
switch (style) {
|
||||
|
@ -199,22 +254,6 @@ static inline WrBorderSide ToWrBorderSide(const gfx::Color& color, const uint8_t
|
|||
return bs;
|
||||
}
|
||||
|
||||
static inline WrPoint ToWrPoint(const LayerPoint point)
|
||||
{
|
||||
WrPoint lp;
|
||||
lp.x = point.x;
|
||||
lp.y = point.y;
|
||||
return lp;
|
||||
}
|
||||
|
||||
static inline WrSize ToWrSize(const LayerSize size)
|
||||
{
|
||||
WrSize ls;
|
||||
ls.width = size.width;
|
||||
ls.height = size.height;
|
||||
return ls;
|
||||
}
|
||||
|
||||
static inline WrBorderRadius ToWrUniformBorderRadius(const LayerSize& aSize)
|
||||
{
|
||||
WrBorderRadius br;
|
||||
|
@ -294,23 +333,6 @@ static inline WrRepeatMode ToWrRepeatMode(uint8_t repeatMode)
|
|||
return WrRepeatMode::Stretch;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrRect ToWrRect(const gfx::RectTyped<T>& rect)
|
||||
{
|
||||
WrRect r;
|
||||
r.x = rect.x;
|
||||
r.y = rect.y;
|
||||
r.width = rect.width;
|
||||
r.height = rect.height;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
|
||||
{
|
||||
return ToWrRect(IntRectToRect(rect));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline WrComplexClipRegion ToWrComplexClipRegion(const gfx::RectTyped<T>& rect,
|
||||
const LayerSize& size)
|
||||
|
@ -321,14 +343,6 @@ static inline WrComplexClipRegion ToWrComplexClipRegion(const gfx::RectTyped<T>&
|
|||
return complex_clip;
|
||||
}
|
||||
|
||||
static inline WrPoint ToWrPoint(const gfx::Point& point)
|
||||
{
|
||||
WrPoint p;
|
||||
p.x = point.x;
|
||||
p.y = point.y;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline WrExternalImageId ToWrExternalImageId(uint64_t aID)
|
||||
{
|
||||
WrExternalImageId id;
|
||||
|
|
|
@ -449,14 +449,6 @@ RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey)
|
|||
bool animatedFramesDiscarded =
|
||||
mAnimationState && aSurfaceKey.Playback() == PlaybackType::eAnimated;
|
||||
|
||||
if (animatedFramesDiscarded && NS_IsMainThread()) {
|
||||
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
|
||||
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
|
||||
// We don't need OnSurfaceDiscardedInternal to handle the animated frames
|
||||
// being discarded because we just did.
|
||||
animatedFramesDiscarded = false;
|
||||
}
|
||||
|
||||
RefPtr<RasterImage> image = this;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"RasterImage::OnSurfaceDiscarded",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamChild.h"
|
||||
#include "mozilla/dom/quota/PQuotaChild.h"
|
||||
#include "mozilla/dom/GamepadEventChannelChild.h"
|
||||
#include "mozilla/dom/GamepadTestChannelChild.h"
|
||||
|
@ -215,6 +216,19 @@ BackgroundChildImpl::DeallocPBlobChild(PBlobChild* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PMemoryStreamChild*
|
||||
BackgroundChildImpl::AllocPMemoryStreamChild(const uint64_t& aSize)
|
||||
{
|
||||
return new mozilla::dom::MemoryStreamChild();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PFileDescriptorSetChild*
|
||||
BackgroundChildImpl::AllocPFileDescriptorSetChild(
|
||||
const FileDescriptor& aFileDescriptor)
|
||||
|
|
|
@ -76,6 +76,12 @@ protected:
|
|||
virtual bool
|
||||
DeallocPBlobChild(PBlobChild* aActor) override;
|
||||
|
||||
virtual PMemoryStreamChild*
|
||||
AllocPMemoryStreamChild(const uint64_t& aSize) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPMemoryStreamChild(PMemoryStreamChild* aActor) override;
|
||||
|
||||
virtual PFileDescriptorSetChild*
|
||||
AllocPFileDescriptorSetChild(const FileDescriptor& aFileDescriptor)
|
||||
override;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/ipc/MemoryStreamParent.h"
|
||||
#include "mozilla/dom/quota/ActorsParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
|
@ -266,6 +267,26 @@ BackgroundParentImpl::DeallocPBlobParent(PBlobParent* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PMemoryStreamParent*
|
||||
BackgroundParentImpl::AllocPMemoryStreamParent(const uint64_t& aSize)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return new mozilla::dom::MemoryStreamParent(aSize);
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
|
||||
{
|
||||
AssertIsInMainProcess();
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BackgroundParentImpl::RecvPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& aParams)
|
||||
|
|
|
@ -69,6 +69,12 @@ protected:
|
|||
virtual bool
|
||||
DeallocPBlobParent(PBlobParent* aActor) override;
|
||||
|
||||
virtual PMemoryStreamParent*
|
||||
AllocPMemoryStreamParent(const uint64_t& aSize) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPMemoryStreamParent(PMemoryStreamParent* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& params) override;
|
||||
|
|
|
@ -15,6 +15,7 @@ include protocol PFileDescriptorSet;
|
|||
include protocol PFileSystemRequest;
|
||||
include protocol PGamepadEventChannel;
|
||||
include protocol PGamepadTestChannel;
|
||||
include protocol PMemoryStream;
|
||||
include protocol PMessagePort;
|
||||
include protocol PCameras;
|
||||
include protocol PQuota;
|
||||
|
@ -59,6 +60,7 @@ sync protocol PBackground
|
|||
manages PFileSystemRequest;
|
||||
manages PGamepadEventChannel;
|
||||
manages PGamepadTestChannel;
|
||||
manages PMemoryStream;
|
||||
manages PMessagePort;
|
||||
manages PCameras;
|
||||
manages PQuota;
|
||||
|
@ -110,6 +112,8 @@ parent:
|
|||
|
||||
async PGamepadTestChannel();
|
||||
|
||||
async PMemoryStream(uint64_t aSize);
|
||||
|
||||
child:
|
||||
async PCache();
|
||||
async PCacheStreamControl();
|
||||
|
|
|
@ -852,7 +852,7 @@ struct JSClass {
|
|||
// application.
|
||||
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT \
|
||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 41)
|
||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 46)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function AsyncIteratorIdentity() {
|
||||
return this;
|
||||
}
|
|
@ -12,10 +12,12 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
#include "jsexn.h"
|
||||
#include "jsiter.h"
|
||||
|
||||
#include "gc/Heap.h"
|
||||
#include "js/Debug.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
|
@ -36,6 +38,16 @@ enum PromiseHandler {
|
|||
PromiseHandlerThrower,
|
||||
PromiseHandlerAsyncFunctionAwaitFulfilled,
|
||||
PromiseHandlerAsyncFunctionAwaitRejected,
|
||||
PromiseHandlerAsyncGeneratorAwaitFulfilled,
|
||||
PromiseHandlerAsyncGeneratorAwaitRejected,
|
||||
|
||||
// Async Iteration proposal 6.1.1.2.1.
|
||||
// Async iterator handlers take the resolved value and create new iterator
|
||||
// objects. To do so it needs to forward whether the iterator is done. In
|
||||
// spec, this is achieved via the [[Done]] internal slot. We enumerate both
|
||||
// true and false cases here.
|
||||
PromiseHandlerAsyncIteratorValueUnwrapDone,
|
||||
PromiseHandlerAsyncIteratorValueUnwrapNotDone,
|
||||
};
|
||||
|
||||
enum ResolutionMode {
|
||||
|
@ -178,6 +190,7 @@ enum ReactionRecordSlots {
|
|||
ReactionRecordSlot_IncumbentGlobalObject,
|
||||
ReactionRecordSlot_Flags,
|
||||
ReactionRecordSlot_HandlerArg,
|
||||
ReactionRecordSlot_Generator,
|
||||
ReactionRecordSlots,
|
||||
};
|
||||
|
||||
|
@ -185,6 +198,7 @@ enum ReactionRecordSlots {
|
|||
#define REACTION_FLAG_FULFILLED 0x2
|
||||
#define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
|
||||
#define REACTION_FLAG_ASYNC_FUNCTION_AWAIT 0x8
|
||||
#define REACTION_FLAG_ASYNC_GENERATOR_AWAIT 0x10
|
||||
|
||||
// ES2016, 25.4.1.2.
|
||||
class PromiseReactionRecord : public NativeObject
|
||||
|
@ -220,6 +234,22 @@ class PromiseReactionRecord : public NativeObject
|
|||
int32_t flags = this->flags();
|
||||
return flags & REACTION_FLAG_ASYNC_FUNCTION_AWAIT;
|
||||
}
|
||||
void setIsAsyncGeneratorAwait(Handle<AsyncGeneratorObject*> asyncGenObj) {
|
||||
int32_t flags = this->flags();
|
||||
flags |= REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
|
||||
setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
|
||||
|
||||
setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj));
|
||||
}
|
||||
bool isAsyncGeneratorAwait() {
|
||||
int32_t flags = this->flags();
|
||||
return flags & REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
|
||||
}
|
||||
AsyncGeneratorObject* asyncGenerator() {
|
||||
MOZ_ASSERT(isAsyncGeneratorAwait());
|
||||
return &getFixedSlot(ReactionRecordSlot_Generator).toObject()
|
||||
.as<AsyncGeneratorObject>();
|
||||
}
|
||||
Value handler() {
|
||||
MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
|
||||
uint32_t slot = targetState() == JS::PromiseState::Fulfilled
|
||||
|
@ -844,6 +874,34 @@ AsyncFunctionAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord
|
|||
return true;
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(reaction->isAsyncGeneratorAwait());
|
||||
|
||||
RootedValue handlerVal(cx, reaction->handler());
|
||||
RootedValue argument(cx, reaction->handlerArg());
|
||||
Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
|
||||
|
||||
int32_t handlerNum = int32_t(handlerVal.toNumber());
|
||||
MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled ||
|
||||
handlerNum == PromiseHandlerAsyncGeneratorAwaitRejected);
|
||||
|
||||
// Await's handlers don't return a value, nor throw exception.
|
||||
// They fail only on OOM.
|
||||
if (handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled) {
|
||||
if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument))
|
||||
return false;
|
||||
} else {
|
||||
if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
|
||||
return false;
|
||||
}
|
||||
|
||||
rval.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.2.1.
|
||||
/**
|
||||
* Callback triggering the fulfill/reject reaction for a resolved Promise,
|
||||
|
@ -882,6 +940,8 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
|
|||
Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
|
||||
if (reaction->isAsyncFunctionAwait())
|
||||
return AsyncFunctionAwaitPromiseReactionJob(cx, reaction, args.rval());
|
||||
if (reaction->isAsyncGeneratorAwait())
|
||||
return AsyncGeneratorAwaitPromiseReactionJob(cx, reaction, args.rval());
|
||||
|
||||
// Step 3.
|
||||
RootedValue handlerVal(cx, reaction->handler());
|
||||
|
@ -898,11 +958,21 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
|
|||
// Step 4.
|
||||
if (handlerNum == PromiseHandlerIdentity) {
|
||||
handlerResult = argument;
|
||||
} else {
|
||||
} else if (handlerNum == PromiseHandlerThrower) {
|
||||
// Step 5.
|
||||
MOZ_ASSERT(handlerNum == PromiseHandlerThrower);
|
||||
resolutionMode = RejectMode;
|
||||
handlerResult = argument;
|
||||
} else {
|
||||
MOZ_ASSERT(handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone ||
|
||||
handlerNum == PromiseHandlerAsyncIteratorValueUnwrapNotDone);
|
||||
|
||||
bool done = handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone;
|
||||
// Async Iteration proposal 6.1.1.2.1 step 1.
|
||||
RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
|
||||
if (!resultObj)
|
||||
return false;
|
||||
|
||||
handlerResult = ObjectValue(*resultObj);
|
||||
}
|
||||
} else {
|
||||
// Step 6.
|
||||
|
@ -2191,6 +2261,344 @@ js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, Hand
|
|||
return PerformPromiseThenWithReaction(cx, promise, reaction);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 5.1 steps 2-9.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value)
|
||||
{
|
||||
// Step 2.
|
||||
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
|
||||
if (!promise)
|
||||
return false;
|
||||
|
||||
// Steps 3.
|
||||
if (!ResolvePromiseInternal(cx, promise, value))
|
||||
return false;
|
||||
|
||||
// Steps 4-5.
|
||||
RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitFulfilled));
|
||||
RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitRejected));
|
||||
|
||||
RootedObject incumbentGlobal(cx);
|
||||
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
|
||||
return false;
|
||||
|
||||
// Step 6 (skipped).
|
||||
|
||||
// Steps 7-8.
|
||||
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, nullptr,
|
||||
onFulfilled, onRejected,
|
||||
nullptr, nullptr,
|
||||
incumbentGlobal));
|
||||
if (!reaction)
|
||||
return false;
|
||||
|
||||
reaction->setIsAsyncGeneratorAwait(asyncGenObj);
|
||||
|
||||
// Step 9.
|
||||
return PerformPromiseThenWithReaction(cx, promise, reaction);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
|
||||
// Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
|
||||
// Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
|
||||
bool
|
||||
js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
|
||||
{
|
||||
// Step 1.
|
||||
RootedValue thisVal(cx, args.thisv());
|
||||
|
||||
// Step 2.
|
||||
RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
|
||||
if (!resultPromise)
|
||||
return false;
|
||||
|
||||
// Step 3.
|
||||
if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
|
||||
// Step 3.a.
|
||||
RootedValue badGeneratorError(cx);
|
||||
if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
|
||||
return false;
|
||||
|
||||
// Step 3.b.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
|
||||
return false;
|
||||
|
||||
// Step 3.c.
|
||||
args.rval().setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
|
||||
Rooted<AsyncFromSyncIteratorObject*> asyncIter(
|
||||
cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
|
||||
|
||||
// Step 4.
|
||||
RootedObject iter(cx, asyncIter->iterator());
|
||||
|
||||
RootedValue resultVal(cx);
|
||||
RootedValue func(cx);
|
||||
if (completionKind == CompletionKind::Normal) {
|
||||
// 6.1.3.2.1 steps 5-6 (partially).
|
||||
if (!GetProperty(cx, iter, iter, cx->names().next, &func))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
} else if (completionKind == CompletionKind::Return) {
|
||||
// 6.1.3.2.2 steps 5-6.
|
||||
if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
// Step 7.
|
||||
if (func.isNullOrUndefined()) {
|
||||
// Step 7.a.
|
||||
RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
|
||||
if (!resultObj)
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
RootedValue resultVal(cx, ObjectValue(*resultObj));
|
||||
|
||||
// Step 7.b.
|
||||
if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
// Step 7.c.
|
||||
args.rval().setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// 6.1.3.2.3 steps 5-6.
|
||||
MOZ_ASSERT(completionKind == CompletionKind::Throw);
|
||||
if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
// Step 7.
|
||||
if (func.isNullOrUndefined()) {
|
||||
// Step 7.a.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
// Step 7.b.
|
||||
args.rval().setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.3.2.1 steps 5-6 (partially).
|
||||
// 6.1.3.2.2, 6.1.3.2.3 steps 8-9.
|
||||
RootedValue iterVal(cx, ObjectValue(*iter));
|
||||
FixedInvokeArgs<1> args2(cx);
|
||||
args2[0].set(args.get(0));
|
||||
if (!js::Call(cx, func, iterVal, args2, &resultVal))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
// 6.1.3.2.1 steps 5-6 (partially).
|
||||
// 6.1.3.2.2, 6.1.3.2.3 steps 10.
|
||||
if (!resultVal.isObject()) {
|
||||
CheckIsObjectKind kind;
|
||||
switch (completionKind) {
|
||||
case CompletionKind::Normal:
|
||||
kind = CheckIsObjectKind::IteratorNext;
|
||||
break;
|
||||
case CompletionKind::Throw:
|
||||
kind = CheckIsObjectKind::IteratorThrow;
|
||||
break;
|
||||
case CompletionKind::Return:
|
||||
kind = CheckIsObjectKind::IteratorReturn;
|
||||
break;
|
||||
}
|
||||
MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
}
|
||||
|
||||
RootedObject resultObj(cx, &resultVal.toObject());
|
||||
|
||||
// Following step numbers are for 6.1.3.2.1.
|
||||
// For 6.1.3.2.2 and 6.1.3.2.3, steps 7-16 corresponds to steps 11-20.
|
||||
|
||||
// Steps 7-8.
|
||||
RootedValue value(cx);
|
||||
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
|
||||
// Steps 9-10.
|
||||
RootedValue doneVal(cx);
|
||||
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
|
||||
return AbruptRejectPromise(cx, args, resultPromise, nullptr);
|
||||
bool done = ToBoolean(doneVal);
|
||||
|
||||
// Step 11.
|
||||
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
|
||||
if (!promise)
|
||||
return false;
|
||||
|
||||
// Step 12.
|
||||
if (!ResolvePromiseInternal(cx, promise, value))
|
||||
return false;
|
||||
|
||||
// Steps 13-14.
|
||||
RootedValue onFulfilled(cx, Int32Value(done
|
||||
? PromiseHandlerAsyncIteratorValueUnwrapDone
|
||||
: PromiseHandlerAsyncIteratorValueUnwrapNotDone));
|
||||
|
||||
RootedObject incumbentGlobal(cx);
|
||||
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
|
||||
return false;
|
||||
|
||||
// Step 15.
|
||||
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
|
||||
UndefinedHandleValue,
|
||||
nullptr, nullptr,
|
||||
incumbentGlobal));
|
||||
if (!reaction)
|
||||
return false;
|
||||
|
||||
if (!PerformPromiseThenWithReaction(cx, promise, reaction))
|
||||
return false;
|
||||
|
||||
// Step 16.
|
||||
args.rval().setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.3.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value, bool done)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
|
||||
|
||||
// Step 4.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
// Step 6.
|
||||
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
|
||||
if (!promise)
|
||||
return false;
|
||||
|
||||
// Step 7.
|
||||
if (!ResolvePromiseInternal(cx, promise, value))
|
||||
return false;
|
||||
|
||||
// Steps 8-9.
|
||||
RootedValue onFulfilled(cx, Int32Value(done
|
||||
? PromiseHandlerAsyncIteratorValueUnwrapDone
|
||||
: PromiseHandlerAsyncIteratorValueUnwrapNotDone));
|
||||
|
||||
RootedObject incumbentGlobal(cx);
|
||||
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
|
||||
return false;
|
||||
|
||||
// Step 10.
|
||||
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
|
||||
UndefinedHandleValue,
|
||||
nullptr, nullptr,
|
||||
incumbentGlobal));
|
||||
if (!reaction)
|
||||
return false;
|
||||
|
||||
if (!PerformPromiseThenWithReaction(cx, promise, reaction))
|
||||
return false;
|
||||
|
||||
// Step 11.
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
|
||||
return false;
|
||||
|
||||
// Step 12.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.4.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue exception)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Steps 2-3.
|
||||
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
|
||||
|
||||
// Step 4.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Step 5.
|
||||
RootedObject resultPromise(cx, request->promise());
|
||||
|
||||
// Step 6.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
|
||||
return false;
|
||||
|
||||
// Step 7.
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
|
||||
return false;
|
||||
|
||||
// Step 8.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 6.4.3.6.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
|
||||
CompletionKind completionKind, HandleValue completionValue,
|
||||
MutableHandleValue result)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
|
||||
// Step 2.
|
||||
RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
|
||||
if (!resultPromise)
|
||||
return false;
|
||||
|
||||
// Step 3.
|
||||
if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) {
|
||||
// Step 3.a.
|
||||
RootedValue badGeneratorError(cx);
|
||||
if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError))
|
||||
return false;
|
||||
|
||||
// Step 3.b.
|
||||
if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
|
||||
return false;
|
||||
|
||||
// Step 3.c.
|
||||
result.setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
|
||||
Rooted<AsyncGeneratorObject*> asyncGenObj(
|
||||
cx, &asyncGenVal.toObject().as<AsyncGeneratorObject>());
|
||||
|
||||
// Step 5 (reordered).
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorRequest::create(cx, completionKind, completionValue, resultPromise));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
// Steps 4, 6.
|
||||
if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request))
|
||||
return false;
|
||||
|
||||
// Step 7.
|
||||
if (!asyncGenObj->isExecuting()) {
|
||||
// Step 8.
|
||||
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 9.
|
||||
result.setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.
|
||||
bool
|
||||
js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
|
|
@ -135,6 +135,26 @@ AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise);
|
|||
MOZ_MUST_USE bool
|
||||
AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
|
||||
|
||||
class AsyncGeneratorObject;
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value, bool done);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue exception);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, CompletionKind completionKind,
|
||||
HandleValue completionValue, MutableHandleValue result);
|
||||
|
||||
bool
|
||||
AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind);
|
||||
|
||||
/**
|
||||
* A PromiseTask represents a task that can be dispatched to a helper thread
|
||||
* (via StartPromiseTask), executed (by implementing PromiseTask::execute()),
|
||||
|
|
|
@ -778,3 +778,15 @@ frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fu
|
|||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
|
||||
return compiler.compileStandaloneFunction(fun, NotGenerator, AsyncFunction, parameterListEnd);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
const Maybe<uint32_t>& parameterListEnd)
|
||||
{
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
|
||||
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,12 @@ CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
|
|||
JS::SourceBufferHolder& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
const mozilla::Maybe<uint32_t>& parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
|
|
|
@ -2004,11 +2004,15 @@ class ForOfLoopControl : public LoopControl
|
|||
|
||||
bool allowSelfHosted_;
|
||||
|
||||
IteratorKind iterKind_;
|
||||
|
||||
public:
|
||||
ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted)
|
||||
ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
|
||||
IteratorKind iterKind)
|
||||
: LoopControl(bce, StatementKind::ForOfLoop),
|
||||
iterDepth_(iterDepth),
|
||||
allowSelfHosted_(allowSelfHosted)
|
||||
allowSelfHosted_(allowSelfHosted),
|
||||
iterKind_(iterKind)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2064,7 +2068,7 @@ class ForOfLoopControl : public LoopControl
|
|||
bool emitIteratorClose(BytecodeEmitter* bce,
|
||||
CompletionKind completionKind = CompletionKind::Normal) {
|
||||
ptrdiff_t start = bce->offset();
|
||||
if (!bce->emitIteratorClose(completionKind, allowSelfHosted_))
|
||||
if (!bce->emitIteratorClose(iterKind_, completionKind, allowSelfHosted_))
|
||||
return false;
|
||||
ptrdiff_t end = bce->offset();
|
||||
return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
|
||||
|
@ -3676,6 +3680,18 @@ BytecodeEmitter::emitFinishIteratorResult(bool done)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitToIteratorResult(bool done)
|
||||
{
|
||||
if (!emitPrepareIteratorResult()) // VALUE OBJ
|
||||
return false;
|
||||
if (!emit1(JSOP_SWAP)) // OBJ VALUE
|
||||
return false;
|
||||
if (!emitFinishIteratorResult(done)) // RESULT
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
|
||||
{
|
||||
|
@ -5210,7 +5226,8 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false */)
|
||||
BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
|
||||
bool allowSelfHosted /* = false */)
|
||||
{
|
||||
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
|
||||
".next() iteration is prohibited in self-hosted code because it "
|
||||
|
@ -5224,6 +5241,12 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false
|
|||
return false;
|
||||
if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
|
||||
return false;
|
||||
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAwait()) // ... RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
@ -5231,7 +5254,8 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted /* = false
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = CompletionKind::Normal */,
|
||||
BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync */,
|
||||
CompletionKind completionKind /* = CompletionKind::Normal */,
|
||||
bool allowSelfHosted /* = false */)
|
||||
{
|
||||
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
|
||||
|
@ -5316,6 +5340,11 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
|
|||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAwait()) // ... ... RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
if (completionKind == CompletionKind::Throw) {
|
||||
if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
|
||||
return false;
|
||||
|
@ -5325,7 +5354,7 @@ BytecodeEmitter::emitIteratorClose(CompletionKind completionKind /* = Completion
|
|||
if (!tryCatch->emitCatch()) // ... RET ITER RESULT
|
||||
return false;
|
||||
|
||||
// Just ignore the exception thrown by call.
|
||||
// Just ignore the exception thrown by call and await.
|
||||
if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
|
||||
return false;
|
||||
if (!emit1(JSOP_POP)) // ... RET ITER RESULT
|
||||
|
@ -6746,6 +6775,63 @@ BytecodeEmitter::emitIterator()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitAsyncIterator()
|
||||
{
|
||||
// Convert iterable to iterator.
|
||||
if (!emit1(JSOP_DUP)) // OBJ OBJ
|
||||
return false;
|
||||
if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) // OBJ OBJ @@ASYNCITERATOR
|
||||
return false;
|
||||
if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
|
||||
return false;
|
||||
|
||||
IfThenElseEmitter ifAsyncIterIsUndefined(this);
|
||||
if (!emit1(JSOP_DUP)) // OBJ ITERFN ITERFN
|
||||
return false;
|
||||
if (!emit1(JSOP_UNDEFINED)) // OBJ ITERFN ITERFN UNDEF
|
||||
return false;
|
||||
if (!emit1(JSOP_EQ)) // OBJ ITERFN EQ
|
||||
return false;
|
||||
if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_POP)) // OBJ
|
||||
return false;
|
||||
if (!emit1(JSOP_DUP)) // OBJ OBJ
|
||||
return false;
|
||||
if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
|
||||
return false;
|
||||
if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
|
||||
return false;
|
||||
if (!emit1(JSOP_SWAP)) // ITERFN OBJ
|
||||
return false;
|
||||
if (!emitCall(JSOP_CALLITER, 0)) // ITER
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALLITER);
|
||||
if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_TOASYNCITER)) // ITER
|
||||
return false;
|
||||
|
||||
if (!ifAsyncIterIsUndefined.emitElse()) // OBJ ITERFN
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_SWAP)) // ITERFN OBJ
|
||||
return false;
|
||||
if (!emitCall(JSOP_CALLITER, 0)) // ITER
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALLITER);
|
||||
if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
|
||||
return false;
|
||||
|
||||
if (!ifAsyncIterIsUndefined.emitEnd()) // ITER
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitSpread(bool allowSelfHosted)
|
||||
{
|
||||
|
@ -6799,7 +6885,7 @@ BytecodeEmitter::emitSpread(bool allowSelfHosted)
|
|||
|
||||
if (!emitDupAt(2)) // ITER ARR I ITER
|
||||
return false;
|
||||
if (!emitIteratorNext(nullptr, allowSelfHosted)) // ITER ARR I RESULT
|
||||
if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted)) // ITER ARR I RESULT
|
||||
return false;
|
||||
if (!emit1(JSOP_DUP)) // ITER ARR I RESULT RESULT
|
||||
return false;
|
||||
|
@ -6899,6 +6985,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
MOZ_ASSERT(forOfHead->isKind(PNK_FOROF));
|
||||
MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
|
||||
|
||||
unsigned iflags = forOfLoop->pn_iflags;
|
||||
IteratorKind iterKind = (iflags & JSITER_FORAWAITOF)
|
||||
? IteratorKind::Async
|
||||
: IteratorKind::Sync;
|
||||
MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
|
||||
MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox()->isAsync());
|
||||
|
||||
ParseNode* forHeadExpr = forOfHead->pn_kid3;
|
||||
|
||||
// Certain builtins (e.g. Array.from) are implemented in self-hosting
|
||||
|
@ -6914,8 +7007,13 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
// Evaluate the expression being iterated.
|
||||
if (!emitTree(forHeadExpr)) // ITERABLE
|
||||
return false;
|
||||
if (!emitIterator()) // ITER
|
||||
return false;
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAsyncIterator()) // ITER
|
||||
return false;
|
||||
} else {
|
||||
if (!emitIterator()) // ITER
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t iterDepth = stackDepth;
|
||||
|
||||
|
@ -6926,7 +7024,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
if (!emit1(JSOP_UNDEFINED)) // ITER RESULT UNDEF
|
||||
return false;
|
||||
|
||||
ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter);
|
||||
ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
|
||||
|
||||
// Annotate so IonMonkey can find the loop-closing jump.
|
||||
unsigned noteIndex;
|
||||
|
@ -7022,7 +7120,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
if (!emitDupAt(1)) // ITER UNDEF ITER
|
||||
return false;
|
||||
|
||||
if (!emitIteratorNext(forOfHead, allowSelfHostedIter)) // ITER UNDEF RESULT
|
||||
if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter)) // ITER UNDEF RESULT
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_SWAP)) // ITER RESULT UNDEF
|
||||
|
@ -7841,7 +7939,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
|||
MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
|
||||
if (funbox->isAsync()) {
|
||||
MOZ_ASSERT(!needsProto);
|
||||
return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow());
|
||||
return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow(),
|
||||
fun->isStarGenerator());
|
||||
}
|
||||
|
||||
if (fun->isArrow()) {
|
||||
|
@ -7896,8 +7995,11 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
|||
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
|
||||
switchToPrologue();
|
||||
if (funbox->isAsync()) {
|
||||
if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow()))
|
||||
if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow(),
|
||||
fun->isStarGenerator()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!emitIndex32(JSOP_LAMBDA, index))
|
||||
return false;
|
||||
|
@ -7913,10 +8015,12 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
|||
// initialize the binding name of the function in the current scope.
|
||||
|
||||
bool isAsync = funbox->isAsync();
|
||||
auto emitLambda = [index, isAsync](BytecodeEmitter* bce, const NameLocation&, bool) {
|
||||
bool isStarGenerator = funbox->isStarGenerator();
|
||||
auto emitLambda = [index, isAsync, isStarGenerator](BytecodeEmitter* bce,
|
||||
const NameLocation&, bool) {
|
||||
if (isAsync) {
|
||||
return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
|
||||
/* isArrow = */ false);
|
||||
/* isArrow = */ false, isStarGenerator);
|
||||
}
|
||||
return bce->emitIndexOp(JSOP_LAMBDA, index);
|
||||
};
|
||||
|
@ -7951,7 +8055,8 @@ BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow)
|
||||
BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
|
||||
bool isStarGenerator)
|
||||
{
|
||||
// needsHomeObject can be true for propertyList for extended class.
|
||||
// In that case push both unwrapped and wrapped function, in order to
|
||||
|
@ -7983,8 +8088,13 @@ BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isA
|
|||
if (!emit1(JSOP_DUP))
|
||||
return false;
|
||||
}
|
||||
if (!emit1(JSOP_TOASYNC))
|
||||
return false;
|
||||
if (isStarGenerator) {
|
||||
if (!emit1(JSOP_TOASYNCGEN))
|
||||
return false;
|
||||
} else {
|
||||
if (!emit1(JSOP_TOASYNC))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8355,13 +8465,8 @@ BytecodeEmitter::emitYield(ParseNode* pn)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitAwait(ParseNode* pn)
|
||||
BytecodeEmitter::emitAwait()
|
||||
{
|
||||
MOZ_ASSERT(sc->isFunctionBox());
|
||||
MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
|
||||
|
||||
if (!emitTree(pn->pn_kid))
|
||||
return false;
|
||||
if (!emitGetDotGenerator())
|
||||
return false;
|
||||
if (!emitYieldOp(JSOP_AWAIT))
|
||||
|
@ -8369,16 +8474,34 @@ BytecodeEmitter::emitAwait(ParseNode* pn)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitAwait(ParseNode* pn)
|
||||
{
|
||||
MOZ_ASSERT(sc->isFunctionBox());
|
||||
MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
|
||||
|
||||
if (!emitTree(pn->pn_kid))
|
||||
return false;
|
||||
return emitAwait();
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
{
|
||||
MOZ_ASSERT(sc->isFunctionBox());
|
||||
MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
|
||||
|
||||
bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
|
||||
|
||||
if (!emitTree(iter)) // ITERABLE
|
||||
return false;
|
||||
if (!emitIterator()) // ITER
|
||||
return false;
|
||||
if (isAsyncGenerator) {
|
||||
if (!emitAsyncIterator()) // ITER
|
||||
return false;
|
||||
} else {
|
||||
if (!emitIterator()) // ITER
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initial send value is undefined.
|
||||
if (!emit1(JSOP_UNDEFINED)) // ITER RECEIVED
|
||||
|
@ -8436,7 +8559,8 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
//
|
||||
// If the iterator does not have a "throw" method, it calls IteratorClose
|
||||
// and then throws a TypeError.
|
||||
if (!emitIteratorClose()) // ITER RESULT EXCEPTION
|
||||
IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
|
||||
if (!emitIteratorClose(iterKind)) // ITER RESULT EXCEPTION
|
||||
return false;
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
|
||||
return false;
|
||||
|
@ -8452,6 +8576,12 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
if (!emitCall(JSOP_CALL, 1, iter)) // ITER OLDRESULT RESULT
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
||||
if (isAsyncGenerator) {
|
||||
if (!emitAwait()) // ITER OLDRESULT RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // ITER OLDRESULT RESULT
|
||||
return false;
|
||||
if (!emit1(JSOP_SWAP)) // ITER RESULT OLDRESULT
|
||||
|
@ -8518,6 +8648,11 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAwait()) // ... FTYPE FVALUE RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step v.
|
||||
if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ITER OLDRESULT FTYPE FVALUE RESULT
|
||||
return false;
|
||||
|
@ -8535,6 +8670,12 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
return false;
|
||||
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER OLDRESULT FTYPE FVALUE VALUE
|
||||
return false;
|
||||
|
||||
if (isAsyncGenerator) {
|
||||
if (!emitAwait()) // ITER OLDRESULT FTYPE FVALUE VALUE
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitPrepareIteratorResult()) // ITER OLDRESULT FTYPE FVALUE VALUE RESULT
|
||||
return false;
|
||||
if (!emit1(JSOP_SWAP)) // ITER OLDRESULT FTYPE FVALUE RESULT VALUE
|
||||
|
@ -8590,9 +8731,15 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
return false;
|
||||
if (!emitCall(JSOP_CALL, 1, iter)) // ITER RESULT
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
||||
if (isAsyncGenerator) {
|
||||
if (!emitAwait()) // ITER RESULT RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ITER RESULT
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
MOZ_ASSERT(this->stackDepth == startDepth);
|
||||
|
||||
if (!emitJumpTargetAndPatch(checkResult)) // checkResult:
|
||||
|
@ -8619,6 +8766,11 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
|||
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // VALUE
|
||||
return false;
|
||||
|
||||
if (isAsyncGenerator) {
|
||||
if (!emitAwait()) // VALUE
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(this->stackDepth == startDepth - 1);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define frontend_BytecodeEmitter_h
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsiter.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
|
@ -605,6 +606,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitPrepareIteratorResult();
|
||||
MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
|
||||
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
|
||||
MOZ_MUST_USE bool emitToIteratorResult(bool done);
|
||||
|
||||
MOZ_MUST_USE bool emitGetDotGenerator();
|
||||
|
||||
|
@ -612,6 +614,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitYield(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitYieldOp(JSOp op);
|
||||
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
|
||||
MOZ_MUST_USE bool emitAwait();
|
||||
MOZ_MUST_USE bool emitAwait(ParseNode* pn);
|
||||
|
||||
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
|
||||
|
@ -619,7 +622,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
|
||||
|
||||
MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
|
||||
MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow);
|
||||
MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
|
||||
bool isStarGenerator);
|
||||
|
||||
MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
|
||||
|
||||
|
@ -693,10 +697,14 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
// It will replace that stack value with the corresponding iterator
|
||||
MOZ_MUST_USE bool emitIterator();
|
||||
|
||||
MOZ_MUST_USE bool emitAsyncIterator();
|
||||
|
||||
// Pops iterator from the top of the stack. Pushes the result of |.next()|
|
||||
// onto the stack.
|
||||
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, bool allowSelfHosted = false);
|
||||
MOZ_MUST_USE bool emitIteratorClose(CompletionKind completionKind = CompletionKind::Normal,
|
||||
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
|
||||
bool allowSelfHosted = false);
|
||||
MOZ_MUST_USE bool emitIteratorClose(IteratorKind iterKind = IteratorKind::Sync,
|
||||
CompletionKind completionKind = CompletionKind::Normal,
|
||||
bool allowSelfHosted = false);
|
||||
|
||||
template <typename InnerEmitter>
|
||||
|
|
|
@ -3753,9 +3753,11 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
|
|||
|
||||
GeneratorKind generatorKind = NotGenerator;
|
||||
if (tt == TOK_MUL) {
|
||||
if (asyncKind != SyncFunction) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
if (!asyncIterationSupported()) {
|
||||
if (asyncKind != SyncFunction) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
}
|
||||
}
|
||||
generatorKind = StarGenerator;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
|
@ -3825,9 +3827,11 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo
|
|||
return null();
|
||||
|
||||
if (tt == TOK_MUL) {
|
||||
if (asyncKind != SyncFunction) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
if (!asyncIterationSupported()) {
|
||||
if (asyncKind != SyncFunction) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
}
|
||||
}
|
||||
generatorKind = StarGenerator;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
|
@ -5857,6 +5861,7 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
|
|||
template <class ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
||||
IteratorKind iterKind,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInitialPart,
|
||||
Maybe<ParseContext::Scope>& forLoopLexicalScope,
|
||||
|
@ -5947,6 +5952,11 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
|||
if (!matchInOrOf(&isForIn, &isForOf))
|
||||
return false;
|
||||
|
||||
if (iterKind == IteratorKind::Async && !isForOf) {
|
||||
error(JSMSG_FOR_AWAIT_NOT_OF);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we don't encounter 'in'/'of', we have a for(;;) loop. We've handled
|
||||
// the init expression; the caller handles the rest. Allow the Operand
|
||||
// modifier when regetting: Operand must be used to examine the ';' in
|
||||
|
@ -6020,6 +6030,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
|
|||
ParseContext::Statement stmt(pc, StatementKind::ForLoop);
|
||||
|
||||
bool isForEach = false;
|
||||
IteratorKind iterKind = IteratorKind::Sync;
|
||||
unsigned iflags = 0;
|
||||
|
||||
if (allowsForEachIn()) {
|
||||
|
@ -6035,6 +6046,19 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
|
|||
}
|
||||
}
|
||||
|
||||
if (asyncIterationSupported()) {
|
||||
if (pc->isAsync()) {
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TOK_AWAIT))
|
||||
return null();
|
||||
|
||||
if (matched) {
|
||||
iflags |= JSITER_FORAWAITOF;
|
||||
iterKind = IteratorKind::Async;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||
|
||||
// PNK_FORHEAD, PNK_FORIN, or PNK_FOROF depending on the loop type.
|
||||
|
@ -6072,7 +6096,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
|
|||
//
|
||||
// In either case the subsequent token can be consistently accessed using
|
||||
// TokenStream::None semantics.
|
||||
if (!forHeadStart(yieldHandling, &headKind, &startNode, forLoopLexicalScope,
|
||||
if (!forHeadStart(yieldHandling, iterKind, &headKind, &startNode, forLoopLexicalScope,
|
||||
&iteratedExpr))
|
||||
{
|
||||
return null();
|
||||
|
@ -9288,11 +9312,6 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
|||
|
||||
bool isGenerator = false;
|
||||
bool isAsync = false;
|
||||
if (ltok == TOK_MUL) {
|
||||
isGenerator = true;
|
||||
if (!tokenStream.getToken(<ok))
|
||||
return null();
|
||||
}
|
||||
|
||||
if (ltok == TOK_ASYNC) {
|
||||
// AsyncMethod[Yield, Await]:
|
||||
|
@ -9321,9 +9340,16 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
|
|||
}
|
||||
}
|
||||
|
||||
if (isAsync && isGenerator) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
if (ltok == TOK_MUL) {
|
||||
if (!asyncIterationSupported()) {
|
||||
if (isAsync) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
}
|
||||
}
|
||||
isGenerator = true;
|
||||
if (!tokenStream.getToken(<ok))
|
||||
return null();
|
||||
}
|
||||
|
||||
propAtom.set(nullptr);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jsiter.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
|
@ -821,6 +822,16 @@ class ParserBase : public StrictModeGetter
|
|||
pc->isLegacyGenerator();
|
||||
}
|
||||
|
||||
bool asyncIterationSupported() {
|
||||
#ifdef RELEASE_OR_BETA
|
||||
return false;
|
||||
#else
|
||||
// Expose Async Iteration only to web content until the spec proposal
|
||||
// gets stable.
|
||||
return !options().isProbablySystemOrAddonCode;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool strictMode() { return pc->sc()->strict(); }
|
||||
bool setLocalStrictMode(bool strict) {
|
||||
MOZ_ASSERT(tokenStream.debugHasNoLookahead());
|
||||
|
@ -1175,6 +1186,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
|
||||
Node forStatement(YieldHandling yieldHandling);
|
||||
bool forHeadStart(YieldHandling yieldHandling,
|
||||
IteratorKind iterKind,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInitialPart,
|
||||
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// |jit-test| error: InternalError
|
||||
|
||||
// This tests that attempting to perform ModuleDeclarationInstantation a second
|
||||
// time after a failure throws an error. Doing this would be a bug in the module
|
||||
// loader, which is expected to throw away modules if there is an error
|
||||
// instantiating them.
|
||||
//
|
||||
// The first attempt fails becuase module 'a' is not available. The second
|
||||
// attempt fails because of the previous failure.
|
||||
//
|
||||
// This test exercises the path where the previously instantiated module is
|
||||
// re-instantiated directly.
|
||||
|
||||
let moduleRepo = {};
|
||||
setModuleResolveHook(function(module, specifier) {
|
||||
return moduleRepo[specifier];
|
||||
});
|
||||
let c;
|
||||
try {
|
||||
let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;");
|
||||
c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';");
|
||||
c.declarationInstantiation();
|
||||
} catch (exc) {}
|
||||
c.declarationInstantiation();
|
|
@ -8,6 +8,9 @@
|
|||
// The first attempt fails becuase module 'a' is not available. The second
|
||||
// attempt fails because of the previous failure (it would otherwise succeed as
|
||||
// 'a' is now available).
|
||||
//
|
||||
// This test exercises the path where the previously instantiated module is
|
||||
// encountered as an import.
|
||||
|
||||
let moduleRepo = {};
|
||||
setModuleResolveHook(function(module, specifier) {
|
||||
|
|
|
@ -7,6 +7,6 @@ if (typeof oomTest !== 'function' || !wasmIsSupported()) {
|
|||
|
||||
function foo() {
|
||||
var g = newGlobal();
|
||||
g.eval(`o = new WebAssembly.Instance(new WebAssemby.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);
|
||||
g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);
|
||||
}
|
||||
oomTest(foo);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "jit/VMFunctions.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
@ -3922,6 +3923,50 @@ BaselineCompiler::emit_JSOP_TOASYNC()
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
|
||||
static const VMFunction ToAsyncGenInfo =
|
||||
FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_TOASYNCGEN()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
|
||||
|
||||
prepareVMCall();
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(ToAsyncGenInfo))
|
||||
return false;
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
|
||||
frame.pop();
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
|
||||
static const VMFunction ToAsyncIterInfo =
|
||||
FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_TOASYNCITER()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
|
||||
|
||||
prepareVMCall();
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(ToAsyncIterInfo))
|
||||
return false;
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
|
||||
frame.pop();
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
|
||||
static const VMFunction ThrowObjectCoercibleInfo =
|
||||
FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible, "ThrowObjectCoercible");
|
||||
|
|
|
@ -197,6 +197,8 @@ namespace jit {
|
|||
_(JSOP_RUNONCE) \
|
||||
_(JSOP_REST) \
|
||||
_(JSOP_TOASYNC) \
|
||||
_(JSOP_TOASYNCGEN) \
|
||||
_(JSOP_TOASYNCITER) \
|
||||
_(JSOP_TOID) \
|
||||
_(JSOP_TOSTRING) \
|
||||
_(JSOP_TABLESWITCH) \
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "jit/RangeAnalysis.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/MatchPairs.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
|
@ -10696,6 +10697,28 @@ CodeGenerator::visitToAsync(LToAsync* lir)
|
|||
callVM(ToAsyncInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
|
||||
static const VMFunction ToAsyncGenInfo =
|
||||
FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
|
||||
|
||||
void
|
||||
CodeGenerator::visitToAsyncGen(LToAsyncGen* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->unwrapped()));
|
||||
callVM(ToAsyncGenInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
|
||||
static const VMFunction ToAsyncIterInfo =
|
||||
FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
|
||||
|
||||
void
|
||||
CodeGenerator::visitToAsyncIter(LToAsyncIter* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->unwrapped()));
|
||||
callVM(ToAsyncIterInfo, lir);
|
||||
}
|
||||
|
||||
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
|
||||
MutableHandleValue);
|
||||
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation, "ToIdOperation");
|
||||
|
|
|
@ -296,6 +296,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitTypeOfV(LTypeOfV* lir);
|
||||
void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
|
||||
void visitToAsync(LToAsync* lir);
|
||||
void visitToAsyncGen(LToAsyncGen* lir);
|
||||
void visitToAsyncIter(LToAsyncIter* lir);
|
||||
void visitToIdV(LToIdV* lir);
|
||||
template<typename T> void emitLoadElementT(LLoadElementT* lir, const T& source);
|
||||
void visitLoadElementT(LLoadElementT* lir);
|
||||
|
|
|
@ -2068,13 +2068,13 @@ CompileBackEnd(MIRGenerator* mir)
|
|||
return GenerateCode(mir, lir);
|
||||
}
|
||||
|
||||
// Find a finished builder for the compartment.
|
||||
// Find a finished builder for the runtime.
|
||||
static IonBuilder*
|
||||
GetFinishedBuilder(JSContext* cx, GlobalHelperThreadState::IonBuilderVector& finished)
|
||||
{
|
||||
for (size_t i = 0; i < finished.length(); i++) {
|
||||
IonBuilder* testBuilder = finished[i];
|
||||
if (testBuilder->compartment == CompileCompartment::get(cx->compartment())) {
|
||||
if (testBuilder->script()->runtimeFromAnyThread() == cx->runtime()) {
|
||||
HelperThreadState().remove(finished, &i);
|
||||
return testBuilder;
|
||||
}
|
||||
|
@ -2095,10 +2095,10 @@ AttachFinishedCompilations(JSContext* cx)
|
|||
|
||||
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
|
||||
|
||||
// Incorporate any off thread compilations for the compartment which have
|
||||
// Incorporate any off thread compilations for the runtime which have
|
||||
// finished, failed or have been cancelled.
|
||||
while (true) {
|
||||
// Find a finished builder for the compartment.
|
||||
// Find a finished builder for the runtime.
|
||||
IonBuilder* builder = GetFinishedBuilder(cx, finished);
|
||||
if (!builder)
|
||||
break;
|
||||
|
|
|
@ -2212,6 +2212,12 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_TOASYNC:
|
||||
return jsop_toasync();
|
||||
|
||||
case JSOP_TOASYNCGEN:
|
||||
return jsop_toasyncgen();
|
||||
|
||||
case JSOP_TOASYNCITER:
|
||||
return jsop_toasynciter();
|
||||
|
||||
case JSOP_TOID:
|
||||
return jsop_toid();
|
||||
|
||||
|
@ -12257,6 +12263,34 @@ IonBuilder::jsop_toasync()
|
|||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::jsop_toasyncgen()
|
||||
{
|
||||
MDefinition* unwrapped = current->pop();
|
||||
MOZ_ASSERT(unwrapped->type() == MIRType::Object);
|
||||
|
||||
MToAsyncGen* ins = MToAsyncGen::New(alloc(), unwrapped);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::jsop_toasynciter()
|
||||
{
|
||||
MDefinition* unwrapped = current->pop();
|
||||
MOZ_ASSERT(unwrapped->type() == MIRType::Object);
|
||||
|
||||
MToAsyncIter* ins = MToAsyncIter::New(alloc(), unwrapped);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::jsop_toid()
|
||||
{
|
||||
|
|
|
@ -569,6 +569,8 @@ class IonBuilder
|
|||
AbortReasonOr<Ok> jsop_globalthis();
|
||||
AbortReasonOr<Ok> jsop_typeof();
|
||||
AbortReasonOr<Ok> jsop_toasync();
|
||||
AbortReasonOr<Ok> jsop_toasyncgen();
|
||||
AbortReasonOr<Ok> jsop_toasynciter();
|
||||
AbortReasonOr<Ok> jsop_toid();
|
||||
AbortReasonOr<Ok> jsop_iter(uint8_t flags);
|
||||
AbortReasonOr<Ok> jsop_itermore();
|
||||
|
|
|
@ -1210,6 +1210,22 @@ LIRGenerator::visitToAsync(MToAsync* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitToAsyncGen(MToAsyncGen* ins)
|
||||
{
|
||||
LToAsyncGen* lir = new(alloc()) LToAsyncGen(useRegisterAtStart(ins->input()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitToAsyncIter(MToAsyncIter* ins)
|
||||
{
|
||||
LToAsyncIter* lir = new(alloc()) LToAsyncIter(useRegisterAtStart(ins->input()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitToId(MToId* ins)
|
||||
{
|
||||
|
|
|
@ -121,6 +121,8 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitCompare(MCompare* comp);
|
||||
void visitTypeOf(MTypeOf* ins);
|
||||
void visitToAsync(MToAsync* ins);
|
||||
void visitToAsyncGen(MToAsyncGen* ins);
|
||||
void visitToAsyncIter(MToAsyncIter* ins);
|
||||
void visitToId(MToId* ins);
|
||||
void visitBitNot(MBitNot* ins);
|
||||
void visitBitAnd(MBitAnd* ins);
|
||||
|
|
|
@ -5825,6 +5825,36 @@ class MToAsync
|
|||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
class MToAsyncGen
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
explicit MToAsyncGen(MDefinition* unwrapped)
|
||||
: MUnaryInstruction(unwrapped)
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ToAsyncGen)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
class MToAsyncIter
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
explicit MToAsyncIter(MDefinition* unwrapped)
|
||||
: MUnaryInstruction(unwrapped)
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ToAsyncIter)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
class MToId
|
||||
: public MUnaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
|
|
|
@ -79,6 +79,8 @@ namespace jit {
|
|||
_(BitNot) \
|
||||
_(TypeOf) \
|
||||
_(ToAsync) \
|
||||
_(ToAsyncGen) \
|
||||
_(ToAsyncIter) \
|
||||
_(ToId) \
|
||||
_(BitAnd) \
|
||||
_(BitOr) \
|
||||
|
|
|
@ -364,8 +364,8 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
|
|||
if (!js::array_push(cx, 1, argv.begin()))
|
||||
return false;
|
||||
|
||||
if (MOZ_LIKELY(argv[0].isInt32())) {
|
||||
*length = argv[0].isInt32();
|
||||
if (argv[0].isInt32()) {
|
||||
*length = argv[0].toInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1618,6 +1618,32 @@ class LToAsync : public LCallInstructionHelper<1, 1, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LToAsyncGen : public LCallInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ToAsyncGen)
|
||||
explicit LToAsyncGen(const LAllocation& input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
const LAllocation* unwrapped() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LToAsyncIter : public LCallInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ToAsyncIter)
|
||||
explicit LToAsyncIter(const LAllocation& input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
const LAllocation* unwrapped() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -363,6 +363,8 @@
|
|||
_(Rest) \
|
||||
_(TypeOfV) \
|
||||
_(ToAsync) \
|
||||
_(ToAsyncGen) \
|
||||
_(ToAsyncIter) \
|
||||
_(ToIdV) \
|
||||
_(Floor) \
|
||||
_(FloorF) \
|
||||
|
|
|
@ -591,3 +591,9 @@ MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "P
|
|||
// Iterator
|
||||
MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of iterator is not callable")
|
||||
MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method")
|
||||
|
||||
// Async Iteration
|
||||
MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop should be used with 'of'")
|
||||
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
|
||||
MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
|
||||
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")
|
||||
|
|
|
@ -157,11 +157,19 @@ TestWeakMaps()
|
|||
JSObject* weakMap = JS::NewWeakMapObject(cx);
|
||||
CHECK(weakMap);
|
||||
|
||||
JSObject* key = AllocWeakmapKeyObject();
|
||||
CHECK(key);
|
||||
JSObject* key;
|
||||
JSObject* value;
|
||||
{
|
||||
JS::RootedObject rootedMap(cx, weakMap);
|
||||
|
||||
JSObject* value = AllocPlainObject();
|
||||
CHECK(value);
|
||||
key = AllocWeakmapKeyObject();
|
||||
CHECK(key);
|
||||
|
||||
value = AllocPlainObject();
|
||||
CHECK(value);
|
||||
|
||||
weakMap = rootedMap;
|
||||
}
|
||||
|
||||
{
|
||||
JS::RootedObject rootedMap(cx, weakMap);
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#include "js/StructuredClone.h"
|
||||
#include "js/Utility.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/DateObject.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
|
@ -3615,6 +3616,11 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (IsWrappedAsyncGenerator(fun)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (CanReuseScriptForClone(cx->compartment(), fun, env)) {
|
||||
// If the script is to be reused, either the script can already handle
|
||||
// non-syntactic scopes, or there is only the standard global lexical
|
||||
|
@ -3867,6 +3873,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp
|
|||
introductionLineno = rhs.introductionLineno;
|
||||
introductionOffset = rhs.introductionOffset;
|
||||
hasIntroductionInfo = rhs.hasIntroductionInfo;
|
||||
isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -3979,6 +3986,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version)
|
|||
strictOption = cx->options().strictMode();
|
||||
extraWarningsOption = cx->compartment()->behaviors().extraWarnings(cx);
|
||||
forEachStatementOption = cx->options().forEachStatement();
|
||||
isProbablySystemOrAddonCode = cx->compartment()->isProbablySystemOrAddonCode();
|
||||
werrorOption = cx->options().werror();
|
||||
if (!cx->options().asmJS())
|
||||
asmJSOption = AsmJSOption::Disabled;
|
||||
|
|
|
@ -3879,6 +3879,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
|
|||
forceAsync(false),
|
||||
sourceIsLazy(false),
|
||||
allowHTMLComments(true),
|
||||
isProbablySystemOrAddonCode(false),
|
||||
introductionType(nullptr),
|
||||
introductionLineno(0),
|
||||
introductionOffset(0),
|
||||
|
@ -3915,6 +3916,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
|
|||
bool forceAsync;
|
||||
bool sourceIsLazy;
|
||||
bool allowHTMLComments;
|
||||
bool isProbablySystemOrAddonCode;
|
||||
|
||||
// |introductionType| is a statically allocated C string:
|
||||
// one of "eval", "Function", or "GeneratorFunction".
|
||||
|
@ -5162,7 +5164,8 @@ GetSymbolDescription(HandleSymbol symbol);
|
|||
macro(split) \
|
||||
macro(toPrimitive) \
|
||||
macro(toStringTag) \
|
||||
macro(unscopables)
|
||||
macro(unscopables) \
|
||||
macro(asyncIterator)
|
||||
|
||||
enum class SymbolCode : uint32_t {
|
||||
// There is one SymbolCode for each well-known symbol.
|
||||
|
|
|
@ -649,11 +649,6 @@ JSCompartment::getTemplateLiteralObject(JSContext* cx, HandleObject rawStrings,
|
|||
// registry.
|
||||
MOZ_ASSERT(!templateObj->nonProxyIsExtensible());
|
||||
} else {
|
||||
// Add the template object to the registry before freezing to avoid
|
||||
// needing to call relookupOrAdd.
|
||||
if (!templateLiteralMap_.add(p, rawStrings, templateObj))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(templateObj->nonProxyIsExtensible());
|
||||
RootedValue rawValue(cx, ObjectValue(*rawStrings));
|
||||
if (!DefineProperty(cx, templateObj, cx->names().raw, rawValue, nullptr, nullptr, 0))
|
||||
|
@ -662,6 +657,9 @@ JSCompartment::getTemplateLiteralObject(JSContext* cx, HandleObject rawStrings,
|
|||
return false;
|
||||
if (!FreezeObject(cx, templateObj))
|
||||
return false;
|
||||
|
||||
if (!templateLiteralMap_.relookupOrAdd(p, rawStrings, templateObj))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -975,6 +975,7 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
|
|||
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
|
||||
#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */
|
||||
#define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
|
||||
#define JSITER_FORAWAITOF 0x80 /* for-await-of */
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
RunningWithTrustedPrincipals(JSContext* cx);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "js/CallNonGenericMethod.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
@ -306,6 +307,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args)
|
|||
JSFunction* callerFun = &callerObj->as<JSFunction>();
|
||||
if (IsWrappedAsyncFunction(callerFun))
|
||||
callerFun = GetUnwrappedAsyncFunction(callerFun);
|
||||
else if (IsWrappedAsyncGenerator(callerFun))
|
||||
callerFun = GetUnwrappedAsyncGenerator(callerFun);
|
||||
MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?");
|
||||
|
||||
if (callerFun->strict()) {
|
||||
|
@ -402,13 +405,15 @@ static const JSPropertySpec function_properties[] = {
|
|||
static bool
|
||||
ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
|
||||
{
|
||||
MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
|
||||
bool isAsyncGenerator = IsWrappedAsyncGenerator(fun);
|
||||
|
||||
MOZ_ASSERT_IF(!isAsyncGenerator, fun->isInterpreted() || fun->isAsmJSNative());
|
||||
MOZ_ASSERT(id == NameToId(cx->names().prototype));
|
||||
|
||||
// Assert that fun is not a compiler-created function object, which
|
||||
// must never leak to script or embedding code and then be mutated.
|
||||
// Also assert that fun is not bound, per the ES5 15.3.4.5 ref above.
|
||||
MOZ_ASSERT(!IsInternalFunctionObject(*fun));
|
||||
MOZ_ASSERT_IF(!isAsyncGenerator, !IsInternalFunctionObject(*fun));
|
||||
MOZ_ASSERT(!fun->isBoundFunction());
|
||||
|
||||
// Make the prototype object an instance of Object with the same parent as
|
||||
|
@ -418,7 +423,9 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId
|
|||
bool isStarGenerator = fun->isStarGenerator();
|
||||
Rooted<GlobalObject*> global(cx, &fun->global());
|
||||
RootedObject objProto(cx);
|
||||
if (isStarGenerator)
|
||||
if (isAsyncGenerator)
|
||||
objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global);
|
||||
else if (isStarGenerator)
|
||||
objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
|
||||
else
|
||||
objProto = GlobalObject::getOrCreateObjectPrototype(cx, global);
|
||||
|
@ -434,7 +441,7 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId
|
|||
// non-enumerable, and writable. However, per the 15 July 2013 ES6 draft,
|
||||
// section 15.19.3, the .prototype of a generator function does not link
|
||||
// back with a .constructor.
|
||||
if (!isStarGenerator) {
|
||||
if (!isStarGenerator && !isAsyncGenerator) {
|
||||
RootedValue objVal(cx, ObjectValue(*fun));
|
||||
if (!DefineProperty(cx, proto, cx->names().constructor, objVal, nullptr, nullptr, 0))
|
||||
return false;
|
||||
|
@ -484,11 +491,13 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
|
|||
* - Arrow functions
|
||||
* - Function.prototype
|
||||
*/
|
||||
if (fun->isBuiltin())
|
||||
return true;
|
||||
if (!fun->isConstructor()) {
|
||||
if (!fun->isStarGenerator() && !fun->isLegacyGenerator() && !fun->isAsync())
|
||||
if (!IsWrappedAsyncGenerator(fun)) {
|
||||
if (fun->isBuiltin())
|
||||
return true;
|
||||
if (!fun->isConstructor()) {
|
||||
if (!fun->isStarGenerator() && !fun->isLegacyGenerator() && !fun->isAsync())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ResolveInterpretedFunctionPrototype(cx, fun, id))
|
||||
|
@ -985,6 +994,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
|
|||
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
|
||||
return FunctionToString(cx, unwrapped, prettyPrint);
|
||||
}
|
||||
if (IsWrappedAsyncGenerator(fun)) {
|
||||
RootedFunction unwrapped(cx, GetUnwrappedAsyncGenerator(fun));
|
||||
return FunctionToString(cx, unwrapped, prettyPrint);
|
||||
}
|
||||
|
||||
StringBuffer out(cx);
|
||||
RootedScript script(cx);
|
||||
|
@ -1637,10 +1650,14 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
|||
&mutedErrors);
|
||||
|
||||
const char* introductionType = "Function";
|
||||
if (isAsync)
|
||||
introductionType = "AsyncFunction";
|
||||
else if (generatorKind != NotGenerator)
|
||||
if (isAsync) {
|
||||
if (isStarGenerator)
|
||||
introductionType = "AsyncGenerator";
|
||||
else
|
||||
introductionType = "AsyncFunction";
|
||||
} else if (generatorKind != NotGenerator) {
|
||||
introductionType = "GeneratorFunction";
|
||||
}
|
||||
|
||||
const char* introducerFilename = filename;
|
||||
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
|
||||
|
@ -1767,12 +1784,20 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
|
|||
: SourceBufferHolder::NoOwnership;
|
||||
bool ok;
|
||||
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
|
||||
if (isAsync)
|
||||
ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
else if (isStarGenerator)
|
||||
ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
else
|
||||
ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
if (isAsync) {
|
||||
if (isStarGenerator) {
|
||||
ok = frontend::CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf,
|
||||
parameterListEnd);
|
||||
} else {
|
||||
ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf,
|
||||
parameterListEnd);
|
||||
}
|
||||
} else {
|
||||
if (isStarGenerator)
|
||||
ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
else
|
||||
ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
|
||||
}
|
||||
|
||||
// Step 33.
|
||||
args.rval().setObject(*fun);
|
||||
|
@ -1798,7 +1823,7 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Save the callee before its reset in FunctionConstructor().
|
||||
// Save the callee before it's reset in FunctionConstructor().
|
||||
RootedObject newTarget(cx);
|
||||
if (args.isConstructing())
|
||||
newTarget = &args.newTarget().toObject();
|
||||
|
@ -1830,6 +1855,40 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Save the callee before its reset in FunctionConstructor().
|
||||
RootedObject newTarget(cx);
|
||||
if (args.isConstructing())
|
||||
newTarget = &args.newTarget().toObject();
|
||||
else
|
||||
newTarget = &args.callee();
|
||||
|
||||
if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction))
|
||||
return false;
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||
return false;
|
||||
|
||||
if (!proto) {
|
||||
proto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global());
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedFunction unwrapped(cx, &args.rval().toObject().as<JSFunction>());
|
||||
RootedObject wrapped(cx, WrapAsyncGeneratorWithProto(cx, unwrapped, proto));
|
||||
if (!wrapped)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*wrapped);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSFunction::isBuiltinFunctionConstructor()
|
||||
{
|
||||
|
|
|
@ -647,6 +647,9 @@ Generator(JSContext* cx, unsigned argc, Value* vp);
|
|||
extern bool
|
||||
AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
extern bool
|
||||
AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
// Allocate a new function backed by a JSNative. Note that by default this
|
||||
// creates a singleton object.
|
||||
extern JSFunction*
|
||||
|
|
|
@ -938,28 +938,30 @@ js::GetIteratorObject(JSContext* cx, HandleObject obj, uint32_t flags)
|
|||
return iterator;
|
||||
}
|
||||
|
||||
// ES 2017 draft 7.4.7.
|
||||
JSObject*
|
||||
js::CreateItrResultObject(JSContext* cx, HandleValue value, bool done)
|
||||
js::CreateIterResultObject(JSContext* cx, HandleValue value, bool done)
|
||||
{
|
||||
// FIXME: We can cache the iterator result object shape somewhere.
|
||||
AssertHeapIsIdle();
|
||||
// Step 1 (implicit).
|
||||
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global()));
|
||||
if (!proto)
|
||||
// Step 2.
|
||||
RootedObject resultObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
||||
if (!resultObj)
|
||||
return nullptr;
|
||||
|
||||
RootedPlainObject obj(cx, NewObjectWithGivenProto<PlainObject>(cx, proto));
|
||||
if (!obj)
|
||||
// Step 3.
|
||||
if (!DefineProperty(cx, resultObj, cx->names().value, value))
|
||||
return nullptr;
|
||||
|
||||
if (!DefineProperty(cx, obj, cx->names().value, value))
|
||||
// Step 4.
|
||||
if (!DefineProperty(cx, resultObj, cx->names().done,
|
||||
done ? TrueHandleValue : FalseHandleValue))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedValue doneBool(cx, BooleanValue(done));
|
||||
if (!DefineProperty(cx, obj, cx->names().done, doneBool))
|
||||
return nullptr;
|
||||
|
||||
return obj;
|
||||
// Step 5.
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -210,10 +210,10 @@ ThrowStopIteration(JSContext* cx);
|
|||
|
||||
/*
|
||||
* Create an object of the form { value: VALUE, done: DONE }.
|
||||
* ES6 draft from 2013-09-05, section 25.4.3.4.
|
||||
* ES 2017 draft 7.4.7.
|
||||
*/
|
||||
extern JSObject*
|
||||
CreateItrResultObject(JSContext* cx, HandleValue value, bool done);
|
||||
CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
|
||||
|
||||
extern JSObject*
|
||||
InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
|
||||
|
@ -221,6 +221,8 @@ InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
|
|||
extern JSObject*
|
||||
InitStopIterationClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
enum class IteratorKind { Sync, Async };
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsiter_h */
|
||||
|
|
|
@ -2027,8 +2027,12 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex)
|
|||
case JSOP_LAMBDA:
|
||||
case JSOP_LAMBDA_ARROW:
|
||||
case JSOP_TOASYNC:
|
||||
case JSOP_TOASYNCGEN:
|
||||
return write("FUN");
|
||||
|
||||
case JSOP_TOASYNCITER:
|
||||
return write("ASYNCITER");
|
||||
|
||||
case JSOP_MOREITER:
|
||||
// For stack dump, defIndex == 0 is not used.
|
||||
MOZ_ASSERT(defIndex == 1);
|
||||
|
@ -2071,6 +2075,7 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex)
|
|||
case JSOP_UNINITIALIZED:
|
||||
return write("UNINITIALIZED");
|
||||
|
||||
case JSOP_AWAIT:
|
||||
case JSOP_YIELD:
|
||||
// Printing "yield SOMETHING" is confusing since the operand doesn't
|
||||
// match to the syntax, since the stack operand for "yield 10" is
|
||||
|
|
|
@ -311,6 +311,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/ArgumentsObject.cpp',
|
||||
'vm/ArrayBufferObject.cpp',
|
||||
'vm/AsyncFunction.cpp',
|
||||
'vm/AsyncIteration.cpp',
|
||||
'vm/Caches.cpp',
|
||||
'vm/CallNonGenericMethod.cpp',
|
||||
'vm/CharacterEncoding.cpp',
|
||||
|
@ -753,6 +754,7 @@ selfhosted.inputs = [
|
|||
'builtin/SelfHostingDefines.h',
|
||||
'builtin/Utilities.js',
|
||||
'builtin/Array.js',
|
||||
'builtin/AsyncIteration.js',
|
||||
'builtin/Classes.js',
|
||||
'builtin/Date.js',
|
||||
'builtin/Error.js',
|
||||
|
@ -793,3 +795,6 @@ if CONFIG['GNU_CXX']:
|
|||
# Suppress warnings in third-party code.
|
||||
if CONFIG['CLANG_CXX']:
|
||||
SOURCES['jsdtoa.cpp'].flags += ['-Wno-implicit-fallthrough']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
#include "threading/Thread.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/Compression.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/HelperThreads.h"
|
||||
|
@ -2395,6 +2396,8 @@ ValueToScript(JSContext* cx, HandleValue v, JSFunction** funp = nullptr)
|
|||
// Get unwrapped async function.
|
||||
if (IsWrappedAsyncFunction(fun))
|
||||
fun = GetUnwrappedAsyncFunction(fun);
|
||||
if (IsWrappedAsyncGenerator(fun))
|
||||
fun = GetUnwrappedAsyncGenerator(fun);
|
||||
|
||||
if (!fun->isInterpreted()) {
|
||||
JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_SCRIPTS_ONLY);
|
||||
|
|
|
@ -9,9 +9,6 @@ if (typeof Reflect !== "undefined" && Reflect.parse) {
|
|||
assertEq(Reflect.parse("async function a() {}").body[0].async, true);
|
||||
assertEq(Reflect.parse("() => {}").body[0].async, undefined);
|
||||
|
||||
// Async generators are not allowed (with regards to spec)
|
||||
assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError);
|
||||
|
||||
// No line terminator after async
|
||||
assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async");
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ var names = [
|
|||
"hasInstance",
|
||||
"split",
|
||||
"toPrimitive",
|
||||
"unscopables"
|
||||
"unscopables",
|
||||
"asyncIterator"
|
||||
];
|
||||
|
||||
for (var name of names) {
|
||||
|
|
|
@ -40,6 +40,9 @@ skip script test262/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
|||
skip-if(!Array.prototype.values) script test262/built-ins/Array/prototype/Symbol.iterator.js
|
||||
skip-if(!Array.prototype.values) include test262/built-ins/Array/prototype/values/jstests.list
|
||||
|
||||
# Async generator is non-release-or-beta only.
|
||||
skip-if(release_or_beta) include test262/language/expressions/async-generators/jstests.list
|
||||
skip-if(release_or_beta) include test262/language/statements/async-generator/jstests.list
|
||||
|
||||
#####################################
|
||||
# Test262 tests disabled on browser #
|
||||
|
@ -493,10 +496,6 @@ skip script test262/annexB/language/eval-code/indirect/global-if-decl-else-decl-
|
|||
skip script test262/annexB/language/eval-code/indirect/global-block-decl-eval-global-exsting-global-init.js
|
||||
skip script test262/annexB/language/eval-code/indirect/global-switch-case-eval-global-exsting-global-init.js
|
||||
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1331092
|
||||
skip include test262/language/expressions/async-generators/jstests.list
|
||||
skip include test262/language/statements/async-generator/jstests.list
|
||||
|
||||
# SIMD.
|
||||
skip script test262/built-ins/Simd/check.js
|
||||
skip script test262/built-ins/Simd/from.js
|
||||
|
@ -871,3 +870,11 @@ skip script test262/intl402/PluralRules/prototype/select/tainting.js
|
|||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1340304
|
||||
skip-if(!xulRuntime.shell) script test262/language/module-code/instn-iee-err-circular.js
|
||||
skip-if(!xulRuntime.shell) script test262/language/module-code/instn-iee-err-circular-as.js
|
||||
|
||||
# Async generators are now a thing.
|
||||
skip script test262/language/statements/async-function/early-errors-no-async-generator-n.js
|
||||
|
||||
# Need to be rewritten to follow the change in https://github.com/tc39/proposal-async-iteration/pull/92
|
||||
skip script test262/language/statements/async-generator/yield-star-async-next.js
|
||||
skip script test262/language/statements/async-generator/yield-star-async-return.js
|
||||
skip script test262/language/statements/async-generator/yield-star-async-throw.js
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче