diff --git a/CLOBBER b/CLOBBER
index acdf4b6cff29..269ff19f9f45 100644
--- a/CLOBBER
+++ b/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 1061335 - CLOBBER for Win32 compiler update.
+Bug 609976 - CLOBBER
diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css
index 645ab3d384ac..d354dc2713d2 100644
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -28,7 +28,6 @@ html xul|scrollbar {
background-image: none !important;
border: 0px solid transparent !important;
pointer-events: none;
- opacity: 1;
}
xul|scrollbar[orient="vertical"] {
@@ -56,7 +55,6 @@ xul|scrollbar[orient="horizontal"] xul|thumb {
xul|scrollbar:not([active="true"]),
xul|scrollbar[disabled] {
opacity: 0;
- transition: opacity 1s ease;
}
xul|scrollbarbutton {
diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index fc8928aa36da..b9d2bf969efb 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index ffce04229cc9..d9197012c578 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index f3edc6c260d6..9a6c7d319bf9 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index 6cce451a7299..84684c1215e0 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index ffce04229cc9..d9197012c578 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index 131ce198a071..d55ce8f7482e 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index 29f57f20b0f2..52ca484c87ae 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index b969aaa98df5..9664093845cd 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
- "revision": "63436aa17e7fa3ad521fdeffdc22b81c36e5d69b",
+ "revision": "934b8c3014a3e20dd5d90ecf95f4b6b704dddb1e",
"repo_path": "/integration/gaia-central"
}
diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml
index ddf7a56c18b0..423b426b54a5 100644
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml
index b95704c693f0..6eb79edcafc1 100644
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index 699092edd0d2..ae02f80fd648 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml
index 6882bd535b45..70ac3ec41131 100644
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/browser/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css
index bc5860e7114a..da3b1e3d779c 100644
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -74,3 +74,13 @@ tabpanels {
browser[pending] {
display: none;
}
+
+browser[pendingpaint] {
+ opacity: 0;
+}
+
+tabbrowser[pendingpaint] {
+ background-image: url(chrome://global/skin/spinner.png);
+ background-repeat: no-repeat;
+ background-position: center center;
+}
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index 014b8a1762f8..f48e358dea7f 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -136,6 +136,10 @@
""
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3266,16 +3295,19 @@
let timeoutPromise = new Promise((aResolve, aReject) => {
timeoutId = setTimeout(() => {
+ this._showBusySpinnerRemoteBrowser(toBrowser);
attemptTabSwitch(aResolve, aReject);
}, kTabSwitchTimeout);
});
let paintPromise = new Promise((aResolve, aReject) => {
- toBrowser.addEventListener("MozAfterRemotePaint", function onRemotePaint() {
+ let onRemotePaint = () => {
toBrowser.removeEventListener("MozAfterRemotePaint", onRemotePaint);
+ this._hideBusySpinnerRemoteBrowser(toBrowser);
clearTimeout(timeoutId);
attemptTabSwitch(aResolve, aReject);
- });
+ };
+ toBrowser.addEventListener("MozAfterRemotePaint", onRemotePaint);
toBrowser.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader
.requestNotifyAfterRemotePaint();
diff --git a/browser/components/places/content/browserPlacesViews.js b/browser/components/places/content/browserPlacesViews.js
index e93d60e5d2cc..6b057ea5b201 100644
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1376,7 +1376,7 @@ PlacesToolbar.prototype = {
elt.localName != "menupopup") {
let eltRect = elt.getBoundingClientRect();
let eltIndex = Array.indexOf(this._rootElt.childNodes, elt);
- if (PlacesUIUtils.nodeIsFolder(elt._placesNode) &&
+ if (PlacesUtils.nodeIsFolder(elt._placesNode) &&
!PlacesUIUtils.isContentsReadOnly(elt._placesNode)) {
// This is a folder.
// If we are in the middle of it, drop inside it.
diff --git a/browser/installer/Makefile.in b/browser/installer/Makefile.in
index b04f52cf1ef8..ffb5c647689f 100644
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -137,6 +137,9 @@ DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX)
ifdef CLANG_CXX
DEFINES += -DCLANG_CXX
endif
+ifdef CLANG_CL
+DEFINES += -DCLANG_CL
+endif
libs::
$(MAKE) -C $(DEPTH)/browser/locales langpack
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 037a7d941f7e..03290e42a8bf 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -921,4 +921,7 @@ bin/libfreebl_32int64_3.so
#ifdef CLANG_CXX
@BINPATH@/llvm-symbolizer
#endif
+#ifdef CLANG_CL
+@BINPATH@/clang_rt.asan_dynamic-i386.dll
+#endif
#endif
diff --git a/browser/modules/PluginContent.jsm b/browser/modules/PluginContent.jsm
index c5c560c71de1..1ded633a2c4f 100644
--- a/browser/modules/PluginContent.jsm
+++ b/browser/modules/PluginContent.jsm
@@ -94,6 +94,9 @@ PluginContent.prototype = {
return;
}
+ if (Services.telemetry.canSend) {
+ this._finishRecordingFlashPluginTelemetry();
+ }
this.clearPluginDataCache();
},
@@ -378,6 +381,11 @@ PluginContent.prototype = {
break;
}
+ if (Services.telemetry.canSend && this._getPluginInfo(plugin).mimetype ===
+ "application/x-shockwave-flash") {
+ this._recordFlashPluginTelemetry(eventType, plugin);
+ }
+
// Show the in-content UI if it's not too big. The crashed plugin handler already did this.
if (eventType != "PluginCrashed") {
let overlay = this.getPluginUI(plugin, "main");
@@ -407,6 +415,42 @@ PluginContent.prototype = {
}
},
+ _recordFlashPluginTelemetry: function (eventType, plugin) {
+ if (!this.flashPluginStats) {
+ this.flashPluginStats = {
+ instancesCount: 0,
+ plugins: new WeakSet()
+ };
+ }
+
+ if (!this.flashPluginStats.plugins.has(plugin)) {
+ // Reporting plugin instance and its dimensions only once.
+ this.flashPluginStats.plugins.add(plugin);
+
+ this.flashPluginStats.instancesCount++;
+
+ let pluginRect = plugin.getBoundingClientRect();
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_WIDTH')
+ .add(pluginRect.width);
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_HEIGHT')
+ .add(pluginRect.height);
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_AREA')
+ .add(pluginRect.width * pluginRect.height);
+
+ let state = this._getPluginInfo(plugin).fallbackType;
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_STATES')
+ .add(state);
+ }
+ },
+
+ _finishRecordingFlashPluginTelemetry: function () {
+ if (this.flashPluginStats) {
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_INSTANCES_ON_PAGE')
+ .add(this.flashPluginStats.instancesCount);
+ delete this.flashPluginStats;
+ }
+ },
+
isKnownPlugin: function (objLoadingContent) {
return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
diff --git a/build/Makefile.in b/build/Makefile.in
index 31ddf7cc2dab..b497dbf07980 100644
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -66,6 +66,13 @@ LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
+ifeq (1_1,$(MOZ_ASAN)_$(CLANG_CL))
+# Install the clang-cl runtime library for ASAN next to the binaries we produce.
+CLANG_RT_ASAN_FILES := $(MOZ_CLANG_RT_ASAN_LIB_PATH)
+CLANG_RT_ASAN_DEST = $(FINAL_TARGET)
+INSTALL_TARGETS += CLANG_RT_ASAN
+endif
+
include $(topsrcdir)/config/rules.mk
TARGET_DEPTH = ..
diff --git a/configure.in b/configure.in
index bd1217908254..96b69269af31 100644
--- a/configure.in
+++ b/configure.in
@@ -506,6 +506,11 @@ case "$target" in
if test -z "$CLANG_CL"; then
AC_DEFINE(HAVE_SEH_EXCEPTIONS)
else
+ # Build on clang-cl with MSVC 2013 with fallback emulation.
+ CFLAGS="$CFLAGS -fmsc-version=1800 -fallback"
+ CXXFLAGS="$CXXFLAGS -fmsc-version=1800 -fallback"
+ # Send our CFLAGS to NSS too
+ MOZ_CFLAGS_NSS=1
AC_DEFINE_UNQUOTED(GTEST_HAS_SEH, 0)
fi
@@ -1260,6 +1265,16 @@ MOZ_ARG_ENABLE_BOOL(address-sanitizer,
MOZ_ASAN= )
if test -n "$MOZ_ASAN"; then
MOZ_LLVM_HACKS=1
+ if test -n "$CLANG_CL"; then
+ # Look for clang_rt.asan_dynamic-i386.dll
+ MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-i386.dll
+ # We use MOZ_PATH_PROG in order to get a Windows style path.
+ MOZ_PATH_PROG(MOZ_CLANG_RT_ASAN_LIB_PATH, $MOZ_CLANG_RT_ASAN_LIB)
+ if test -z "$MOZ_CLANG_RT_ASAN_LIB_PATH"; then
+ AC_MSG_ERROR([Couldn't find $MOZ_CLANG_RT_ASAN_LIB. It should be available in the same location as clang-cl.])
+ fi
+ AC_SUBST(MOZ_CLANG_RT_ASAN_LIB_PATH)
+ fi
AC_DEFINE(MOZ_ASAN)
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
fi
@@ -3796,11 +3811,6 @@ dnl system libffi Support
dnl ========================================================
MOZ_CONFIG_FFI()
-# split JS out by default to avoid VS2005 PGO crash (bug 591836).
-if test "$OS_ARCH" = "WINNT"; then
- JS_SHARED_LIBRARY=1
-fi
-
MOZ_ARG_ENABLE_BOOL(shared-js,
[ --enable-shared-js
Create a shared JavaScript library.],
@@ -7953,8 +7963,7 @@ dnl =
dnl ========================================================
MOZ_ARG_HEADER(Static build options)
-if test "$OS_ARCH" = "WINNT"; then
- GKMEDIAS_SHARED_LIBRARY=1
+if test -n "$GKMEDIAS_SHARED_LIBRARY"; then
AC_DEFINE(GKMEDIAS_SHARED_LIBRARY)
fi
AC_SUBST(GKMEDIAS_SHARED_LIBRARY)
diff --git a/content/base/public/FragmentOrElement.h b/content/base/public/FragmentOrElement.h
index c53bf7894672..95c7299a6977 100644
--- a/content/base/public/FragmentOrElement.h
+++ b/content/base/public/FragmentOrElement.h
@@ -412,7 +412,7 @@ public:
/**
* Web components custom element data.
*/
- nsAutoPtr mCustomElementData;
+ nsRefPtr mCustomElementData;
};
protected:
diff --git a/content/base/src/DOMParser.cpp b/content/base/src/DOMParser.cpp
index 04d169424ce4..b9bec3e69b6e 100644
--- a/content/base/src/DOMParser.cpp
+++ b/content/base/src/DOMParser.cpp
@@ -238,18 +238,15 @@ DOMParser::ParseFromStream(nsIInputStream *stream,
// Create a fake channel
nsCOMPtr parserChannel;
- NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nullptr,
- nsDependentCString(contentType), nullptr);
+ NS_NewInputStreamChannel(getter_AddRefs(parserChannel),
+ mDocumentURI,
+ nullptr, // aStream
+ mOriginalPrincipal,
+ nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER,
+ nsDependentCString(contentType));
NS_ENSURE_STATE(parserChannel);
- // More principal-faking here
- nsCOMPtr loadInfo =
- new LoadInfo(mOriginalPrincipal,
- nullptr,
- nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER);
- parserChannel->SetLoadInfo(loadInfo);
-
if (charset) {
parserChannel->SetContentCharset(nsDependentCString(charset));
}
diff --git a/content/base/src/WebSocket.cpp b/content/base/src/WebSocket.cpp
index 1ba4fc4fa0f0..bfde6f97a4ae 100644
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -193,6 +193,8 @@ public:
WorkerPrivate* mWorkerPrivate;
nsAutoPtr mWorkerFeature;
+ nsWeakPtr mWeakLoadGroup;
+
private:
~WebSocketImpl()
{
@@ -528,8 +530,7 @@ WebSocketImpl::DisconnectInternal()
{
AssertIsOnMainThread();
- nsCOMPtr loadGroup;
- GetLoadGroup(getter_AddRefs(loadGroup));
+ nsCOMPtr loadGroup = do_QueryReferent(mWeakLoadGroup);
if (loadGroup) {
loadGroup->RemoveRequest(this, nullptr, NS_OK);
}
@@ -1390,6 +1391,8 @@ WebSocketImpl::InitializeConnection()
NS_ENSURE_SUCCESS(rv, rv);
rv = loadGroup->AddRequest(this, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
+
+ mWeakLoadGroup = do_GetWeakReference(loadGroup);
}
// manually adding loadinfo to the channel since it
diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp
index 9d06af8500b4..188337415703 100644
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5844,12 +5844,7 @@ nsDocument::ProcessTopElementQueue(bool aIsBaseQueue)
{
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
- if (sProcessingStack.isNothing()) {
- // If XPCOM shutdown has reset the processing stack, don't do anything.
- return;
- }
-
- nsTArray& stack = *sProcessingStack;
+ nsTArray>& stack = *sProcessingStack;
uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
if (aIsBaseQueue && firstQueue != 0) {
@@ -5886,7 +5881,7 @@ nsDocument::RegisterEnabled()
}
// static
-Maybe>
+Maybe>>
nsDocument::sProcessingStack;
// static
diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h
index dcb52223036b..3a9f8a3deabe 100644
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -325,6 +325,8 @@ private:
// being created flag.
struct CustomElementData
{
+ NS_INLINE_DECL_REFCOUNTING(CustomElementData)
+
explicit CustomElementData(nsIAtom* aType);
// Objects in this array are transient and empty after each microtask
// checkpoint.
@@ -346,6 +348,9 @@ struct CustomElementData
// Empties the callback queue.
void RunCallbackQueue();
+
+private:
+ virtual ~CustomElementData() {}
};
// The required information for a custom element as defined in:
@@ -1520,7 +1525,7 @@ private:
// CustomElementData in this array, separated by nullptr that
// represent the boundaries of the items in the stack. The first
// queue in the stack is the base element queue.
- static mozilla::Maybe> sProcessingStack;
+ static mozilla::Maybe>> sProcessingStack;
// Flag to prevent re-entrance into base element queue as described in the
// custom elements speicification.
diff --git a/content/base/src/nsHostObjectProtocolHandler.cpp b/content/base/src/nsHostObjectProtocolHandler.cpp
index bf04e2d533ff..0a7ed3a4661e 100644
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -519,7 +519,11 @@ nsHostObjectProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
nsCOMPtr channel;
rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
uri,
- stream);
+ stream,
+ info->mPrincipal,
+ nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER);
+
NS_ENSURE_SUCCESS(rv, rv);
nsString type;
@@ -537,12 +541,6 @@ nsHostObjectProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
return error.ErrorCode();
}
- nsCOMPtr loadInfo =
- new mozilla::LoadInfo(info->mPrincipal,
- nullptr,
- nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER);
- channel->SetLoadInfo(loadInfo);
channel->SetOriginalURI(uri);
channel->SetContentType(NS_ConvertUTF16toUTF8(type));
channel->SetContentLength(size);
diff --git a/content/base/test/chrome/cpows_child.js b/content/base/test/chrome/cpows_child.js
index 8dc79bd497a2..1290d9eb556d 100644
--- a/content/base/test/chrome/cpows_child.js
+++ b/content/base/test/chrome/cpows_child.js
@@ -12,6 +12,9 @@ var is_remote;
error_reporting_test();
dom_test();
xray_test();
+ if (typeof Symbol === "function") {
+ symbol_test();
+ }
compartment_test();
regexp_test();
sync_test();
@@ -119,15 +122,13 @@ function symbol_test()
{
let iterator = Symbol.iterator;
let named = Symbol.for("cpow-test");
- // let unique = Symbol();
let object = {
[iterator]: iterator,
[named]: named,
- // [unique]: unique,
- // "unique": unique
};
- sendSyncMessage("cpows:symbol_test", {}, object);
+ let test = ['a'];
+ sendSyncMessage("cpows:symbol_test", {}, {object: object, test: test});
}
// Parent->Child references should go X->parent.privilegedJunkScope->child.privilegedJunkScope->Y
diff --git a/content/base/test/chrome/cpows_parent.xul b/content/base/test/chrome/cpows_parent.xul
index 74c5437c297b..73876f63f016 100644
--- a/content/base/test/chrome/cpows_parent.xul
+++ b/content/base/test/chrome/cpows_parent.xul
@@ -206,10 +206,16 @@
}
function recvSymbolTest(message) {
- let object = message.objects;
+ let object = message.objects.object;
is(object[Symbol.iterator], Symbol.iterator, "Should use Symbol.iterator");
is(Symbol.keyFor(object[Symbol.for("cpow-test")]), "cpow-test", "Symbols aren't registered correctly");
- // is(object.unique, object[object.unique], "Unique symbols as ids and values don't seem to work");
+ let symbols = Object.getOwnPropertySymbols(object);
+ is(symbols.length, 2, "Object should have two symbol keys");
+ let test = undefined;
+ for (let x of message.objects.test) {
+ test = x;
+ }
+ is(test, "a", "for .. of iteration should work");
}
let systemGlobal = this;
@@ -307,7 +313,9 @@
mm.addMessageListener("cpows:dom_test", recvDomTest);
mm.addMessageListener("cpows:dom_test_after_gc", recvDomTestAfterGC);
mm.addMessageListener("cpows:xray_test", recvXrayTest);
- mm.addMessageListener("cpows:symbol_test", recvSymbolTest);
+ if (typeof Symbol === "function") {
+ mm.addMessageListener("cpows:symbol_test", recvSymbolTest);
+ }
mm.addMessageListener("cpows:compartment_test", recvCompartmentTest);
mm.addMessageListener("cpows:regexp_test", recvRegExpTest);
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index d218f4810825..a6b1136dd1f3 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1655,12 +1655,25 @@ nsDocShell::LoadStream(nsIInputStream *aStream, nsIURI * aURI,
mLoadType = loadType;
+ nsCOMPtr owner;
+ aLoadInfo->GetOwner(getter_AddRefs(owner));
+ nsCOMPtr requestingPrincipal = do_QueryInterface(owner);
+ if (!requestingPrincipal) {
+ requestingPrincipal = nsContentUtils::GetSystemPrincipal();
+ }
+
// build up a channel for this stream.
nsCOMPtr channel;
- NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
- (getter_AddRefs(channel), uri, aStream,
- aContentType, aContentCharset),
- NS_ERROR_FAILURE);
+ nsresult rv =
+ NS_NewInputStreamChannel(getter_AddRefs(channel),
+ uri,
+ aStream,
+ requestingPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
+ aContentType,
+ aContentCharset);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsCOMPtr
uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
@@ -10266,25 +10279,28 @@ nsDocShell::DoURILoad(nsIURI * aURI,
rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, aBaseURI,
getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr loadInfo =
+ new LoadInfo(requestingPrincipal,
+ requestingNode,
+ securityFlags,
+ aContentPolicyType);
+ channel->SetLoadInfo(loadInfo);
}
else {
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel),aURI,
- aSrcdoc,
- NS_LITERAL_CSTRING("text/html"),
- true);
+ rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+ aURI,
+ aSrcdoc,
+ NS_LITERAL_CSTRING("text/html"),
+ requestingNode,
+ requestingPrincipal,
+ securityFlags,
+ aContentPolicyType,
+ true);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr isc = do_QueryInterface(channel);
MOZ_ASSERT(isc);
isc->SetBaseURI(aBaseURI);
}
- // NS_NewInputStreamChannel does not yet attach the loadInfo in nsNetutil.h,
- // hence we have to manually attach the loadInfo for that channel.
- nsCOMPtr loadInfo =
- new LoadInfo(requestingPrincipal,
- requestingNode,
- securityFlags,
- aContentPolicyType);
- channel->SetLoadInfo(loadInfo);
}
nsCOMPtr appCacheChannel =
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 44067714919b..50355c9702fd 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -599,20 +599,7 @@ public:
return false;
}
- virtual const char *className(JSContext *cx,
- JS::Handle wrapper) const MOZ_OVERRIDE;
- virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
-
- // Fundamental traps
- virtual bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible)
- const MOZ_OVERRIDE;
- virtual bool preventExtensions(JSContext *cx,
- JS::Handle proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext* cx,
- JS::Handle proxy,
- JS::Handle id,
- JS::MutableHandle desc)
- const MOZ_OVERRIDE;
+ // Standard internal methods
virtual bool getOwnPropertyDescriptor(JSContext* cx,
JS::Handle proxy,
JS::Handle id,
@@ -631,23 +618,12 @@ public:
bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, JS::Handle proxy,
JS::AutoIdVector &props) const MOZ_OVERRIDE;
-
- virtual bool watch(JSContext *cx, JS::Handle proxy,
- JS::Handle id, JS::Handle callable) const MOZ_OVERRIDE;
- virtual bool unwatch(JSContext *cx, JS::Handle proxy,
- JS::Handle id) const MOZ_OVERRIDE;
- virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
- return false;
- }
- virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
- return false;
- }
-
- // Derived traps
+ virtual bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible)
+ const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx,
+ JS::Handle proxy) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, JS::Handle proxy,
JS::Handle id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, JS::Handle proxy,
- JS::Handle id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, JS::Handle proxy,
JS::Handle receiver,
JS::Handle id,
@@ -657,11 +633,36 @@ public:
JS::Handle id,
bool strict,
JS::MutableHandle vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, JS::Handle proxy,
- JS::AutoIdVector &props) const MOZ_OVERRIDE;
+
+ // SpiderMonkey extensions
+ virtual bool getPropertyDescriptor(JSContext* cx,
+ JS::Handle proxy,
+ JS::Handle id,
+ JS::MutableHandle desc)
+ const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, JS::Handle proxy,
+ JS::Handle id, bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy,
+ JS::AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, JS::Handle proxy,
unsigned flags,
JS::MutableHandle vp) const MOZ_OVERRIDE;
+ virtual const char *className(JSContext *cx,
+ JS::Handle wrapper) const MOZ_OVERRIDE;
+
+ virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
+
+ virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
+ return false;
+ }
+ virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
+ return false;
+ }
+
+ virtual bool watch(JSContext *cx, JS::Handle proxy,
+ JS::Handle id, JS::Handle callable) const MOZ_OVERRIDE;
+ virtual bool unwatch(JSContext *cx, JS::Handle proxy,
+ JS::Handle id) const MOZ_OVERRIDE;
static void ObjectMoved(JSObject *obj, const JSObject *old);
@@ -930,12 +931,12 @@ nsOuterWindowProxy::set(JSContext *cx, JS::Handle proxy,
}
bool
-nsOuterWindowProxy::keys(JSContext *cx, JS::Handle proxy,
- JS::AutoIdVector &props) const
+nsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy,
+ JS::AutoIdVector &props) const
{
// BaseProxyHandler::keys seems to do what we want here: call
// ownPropertyKeys and then filter out the non-enumerable properties.
- return js::BaseProxyHandler::keys(cx, proxy, props);
+ return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
}
bool
diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini
index 8d2e82156f1f..96e0919beb78 100644
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -82,6 +82,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_urlutils_stringify.html]
[test_window_constructor.html]
[test_window_cross_origin_props.html]
+[test_window_define_symbol.html]
[test_window_enumeration.html]
[test_window_extensible.html]
[test_window_indexing.html]
diff --git a/dom/base/test/test_window_define_symbol.html b/dom/base/test/test_window_define_symbol.html
new file mode 100644
index 000000000000..b5b936542d90
--- /dev/null
+++ b/dom/base/test/test_window_define_symbol.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+ Test for Bug 1082672 part 2
+
+
+
+
+Mozilla Bug 1082672
+
+
+
+
+
+
+
+
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 8dfbf4acf9ec..09e8e30d1e2d 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1406,8 +1406,11 @@ XrayAttributeOrMethodKeys(JSContext* cx, JS::Handle wrapper,
// looking at now.
size_t i = list->specs - specList;
for ( ; ids[i] != JSID_VOID; ++i) {
+ // Skip non-enumerable properties and symbol-keyed properties unless
+ // they are specially requested via flags.
if (((flags & JSITER_HIDDEN) ||
(specList[i].flags & JSPROP_ENUMERATE)) &&
+ ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(ids[i])) &&
!props.append(ids[i])) {
return false;
}
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index 6e53ee6f8d49..289747b940e7 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1685,7 +1685,7 @@ InitIds(JSContext* cx, const Prefable* prefableSpecs, jsid* ids)
// because this is only done once per application runtime.
Spec* spec = prefableSpecs->specs;
do {
- if (!InternJSString(cx, *ids, spec->name)) {
+ if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
return false;
}
} while (++ids, (++spec)->name);
diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp
index 66ef905360f7..e798c5a035e6 100644
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -277,7 +277,7 @@ BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle proxy,
if (!JS_GetPrototype(cx, proxy, &proto)) {
return false;
}
- return keys(cx, proxy, props) &&
+ return getOwnEnumerablePropertyKeys(cx, proxy, props) &&
(!proto || js::GetPropertyKeys(cx, proto, 0, &props));
}
@@ -299,13 +299,13 @@ BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
JS::Handle proxy,
JS::AutoIdVector& props) const
{
- return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
+ return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
}
bool
-BaseDOMProxyHandler::keys(JSContext* cx,
- JS::Handle proxy,
- JS::AutoIdVector& props) const
+BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
+ JS::Handle proxy,
+ JS::AutoIdVector& props) const
{
return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
}
@@ -345,7 +345,8 @@ IdToInt32(JSContext* cx, JS::Handle id)
JS::Rooted idval(cx);
double array_index;
int32_t i;
- if (!::JS_IdToValue(cx, id, &idval) ||
+ if (JSID_IS_SYMBOL(id) ||
+ !::JS_IdToValue(cx, id, &idval) ||
!JS::ToNumber(cx, idval, &array_index) ||
!::JS_DoubleIsInt32(array_index, &i)) {
return -1;
diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h
index 0ecdedf74931..7aa264b9e41a 100644
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -50,34 +50,38 @@ public:
: js::BaseProxyHandler(aProxyFamily, aHasPrototype)
{}
- // Implementations of traps that can be implemented in terms of
- // fundamental traps.
- bool enumerate(JSContext* cx, JS::Handle proxy,
- JS::AutoIdVector& props) const MOZ_OVERRIDE;
- bool getPropertyDescriptor(JSContext* cx, JS::Handle proxy,
- JS::Handle id,
- JS::MutableHandle desc) const MOZ_OVERRIDE;
+ // Implementations of methods that can be implemented in terms of
+ // other lower-level methods.
bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy,
JS::Handle id,
JS::MutableHandle desc) const MOZ_OVERRIDE;
+ virtual bool ownPropertyKeys(JSContext* cx, JS::Handle proxy,
+ JS::AutoIdVector &props) const MOZ_OVERRIDE;
+ bool enumerate(JSContext* cx, JS::Handle proxy,
+ JS::AutoIdVector& props) const MOZ_OVERRIDE;
+
+ bool getPropertyDescriptor(JSContext* cx, JS::Handle proxy,
+ JS::Handle id,
+ JS::MutableHandle desc) const MOZ_OVERRIDE;
+
+
+ // We override getOwnEnumerablePropertyKeys() and implement it directly
+ // instead of using the default implementation, which would call
+ // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
+ // unnecessary work during enumeration.
+ virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle proxy,
+ JS::AutoIdVector &props) const MOZ_OVERRIDE;
bool watch(JSContext* cx, JS::Handle proxy, JS::Handle id,
JS::Handle callable) const MOZ_OVERRIDE;
bool unwatch(JSContext* cx, JS::Handle proxy,
JS::Handle id) const MOZ_OVERRIDE;
- virtual bool ownPropertyKeys(JSContext* cx, JS::Handle proxy,
- JS::AutoIdVector &props) const MOZ_OVERRIDE;
- // We override keys() and implement it directly instead of using the
- // default implementation, which would getOwnPropertyNames and then
- // filter out the non-enumerable ones. This avoids doing
- // unnecessary work during enumeration.
- virtual bool keys(JSContext* cx, JS::Handle proxy,
- JS::AutoIdVector &props) const MOZ_OVERRIDE;
protected:
// Hook for subclasses to implement shared ownPropertyKeys()/keys()
// functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
- // or JSITER_OWNONLY | JSITER_HIDDEN (for ownPropertyKeys()).
+ // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for
+ // ownPropertyKeys()).
virtual bool ownPropNames(JSContext* cx, JS::Handle proxy,
unsigned flags,
JS::AutoIdVector& props) const = 0;
@@ -100,7 +104,6 @@ public:
: BaseDOMProxyHandler(&family)
{}
- bool preventExtensions(JSContext *cx, JS::Handle proxy) const MOZ_OVERRIDE;
bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id,
JS::MutableHandle desc) const MOZ_OVERRIDE
{
@@ -110,15 +113,16 @@ public:
virtual bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id,
JS::MutableHandle desc, bool* defined)
const;
+ bool delete_(JSContext* cx, JS::Handle proxy,
+ JS::Handle id, bool* bp) const MOZ_OVERRIDE;
+ bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible)
+ const MOZ_OVERRIDE;
+ bool preventExtensions(JSContext *cx, JS::Handle proxy) const MOZ_OVERRIDE;
+ bool has(JSContext* cx, JS::Handle proxy, JS::Handle id,
+ bool* bp) const MOZ_OVERRIDE;
bool set(JSContext *cx, JS::Handle proxy, JS::Handle receiver,
JS::Handle id, bool strict, JS::MutableHandle vp)
const MOZ_OVERRIDE;
- bool delete_(JSContext* cx, JS::Handle proxy,
- JS::Handle id, bool* bp) const MOZ_OVERRIDE;
- bool has(JSContext* cx, JS::Handle proxy, JS::Handle id,
- bool* bp) const MOZ_OVERRIDE;
- bool isExtensible(JSContext *cx, JS::Handle proxy, bool *extensible)
- const MOZ_OVERRIDE;
/*
* If assigning to proxy[id] hits a named setter with OverrideBuiltins or
diff --git a/dom/bluetooth2/bluedroid/b2g_bdroid_buildcfg.h b/dom/bluetooth2/bluedroid/b2g_bdroid_buildcfg.h
index f28123bef5be..f6982409efb6 100644
--- a/dom/bluetooth2/bluedroid/b2g_bdroid_buildcfg.h
+++ b/dom/bluetooth2/bluedroid/b2g_bdroid_buildcfg.h
@@ -39,4 +39,9 @@
/* CHLD values */
#define BTA_AG_CHLD_VAL "(0,1,2,3)"
+/* BLE Feature */
+#define BTA_GATT_INCLUDED TRUE
+#define BLE_INCLUDED TRUE
+#define SMP_INCLUDED TRUE
+
#endif /* B2G_BDROID_BUILDCFG_H */
diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h
index 23b6eeaa0c3b..16fd6a018eb7 100644
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -66,7 +66,11 @@ public:
void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth);
-
+ void TexImage3D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const Nullable &pixels,
+ ErrorResult& rv);
void TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
diff --git a/dom/canvas/WebGL2ContextTextures.cpp b/dom/canvas/WebGL2ContextTextures.cpp
index 21028d09e5b6..106349b1cfec 100644
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -204,6 +204,119 @@ WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat
}
}
+void
+WebGL2Context::TexImage3D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const Nullable &pixels,
+ ErrorResult& rv)
+{
+ if (IsContextLost())
+ return;
+
+ void* data;
+ size_t dataLength;
+ js::Scalar::Type jsArrayType;
+ if (pixels.IsNull()) {
+ data = nullptr;
+ dataLength = 0;
+ jsArrayType = js::Scalar::TypeMax;
+ } else {
+ const ArrayBufferView& view = pixels.Value();
+ view.ComputeLengthAndData();
+
+ data = view.Data();
+ dataLength = view.Length();
+ jsArrayType = JS_GetArrayBufferViewType(view.Obj());
+ }
+
+ const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
+ const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
+
+ if (!ValidateTexImageTarget(target, func, dims))
+ return;
+
+ TexImageTarget texImageTarget = target;
+
+ if (!ValidateTexImage(texImageTarget, level, internalformat,
+ 0, 0, 0,
+ width, height, depth,
+ border, format, type, func, dims))
+ {
+ return;
+ }
+
+ if (!ValidateTexInputData(type, jsArrayType, func, dims))
+ return;
+
+ TexInternalFormat effectiveInternalFormat =
+ EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
+
+ if (effectiveInternalFormat == LOCAL_GL_NONE) {
+ return ErrorInvalidOperation("texImage3D: bad combination of internalformat and type");
+ }
+
+ // we need to find the exact sized format of the source data. Slightly abusing
+ // EffectiveInternalFormatFromInternalFormatAndType for that purpose. Really, an unsized source format
+ // is the same thing as an unsized internalformat.
+ TexInternalFormat effectiveSourceFormat =
+ EffectiveInternalFormatFromInternalFormatAndType(format, type);
+ MOZ_ASSERT(effectiveSourceFormat != LOCAL_GL_NONE); // should have validated format/type combo earlier
+ const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
+ MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
+ size_t srcTexelSize = srcbitsPerTexel / 8;
+
+ CheckedUint32 checked_neededByteLength =
+ GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
+
+ if (!checked_neededByteLength.isValid())
+ return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
+
+ uint32_t bytesNeeded = checked_neededByteLength.value();
+
+ if (dataLength && dataLength < bytesNeeded)
+ return ErrorInvalidOperation("texImage3D: not enough data for operation (need %d, have %d)",
+ bytesNeeded, dataLength);
+
+ WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
+
+ if (!tex)
+ return ErrorInvalidOperation("texImage3D: no texture is bound to this target");
+
+ if (tex->IsImmutable()) {
+ return ErrorInvalidOperation(
+ "texImage3D: disallowed because the texture "
+ "bound to this target has already been made immutable by texStorage3D");
+ }
+
+ GLenum driverType = LOCAL_GL_NONE;
+ GLenum driverInternalFormat = LOCAL_GL_NONE;
+ GLenum driverFormat = LOCAL_GL_NONE;
+ DriverFormatsFromEffectiveInternalFormat(gl,
+ effectiveInternalFormat,
+ &driverInternalFormat,
+ &driverFormat,
+ &driverType);
+
+ MakeContextCurrent();
+ GetAndFlushUnderlyingGLErrors();
+ gl->fTexImage3D(texImageTarget.get(), level,
+ driverInternalFormat,
+ width, height, depth,
+ 0, driverFormat, driverType,
+ data);
+ GLenum error = GetAndFlushUnderlyingGLErrors();
+ if (error) {
+ return GenerateWarning("texImage3D generated error %s", ErrorName(error));
+ }
+
+ tex->SetImageInfo(texImageTarget, level,
+ width, height, depth,
+ effectiveInternalFormat,
+ data ? WebGLImageDataStatus::InitializedImageData
+ : WebGLImageDataStatus::UninitializedImageData);
+}
+
void
WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp
index 74e67e38a489..be3cd4901871 100644
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -922,7 +922,11 @@ WebGLContext::GenerateMipmap(GLenum rawTarget)
const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D)
? LOCAL_GL_TEXTURE_2D
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- if (!tex->HasImageInfoAt(imageTarget, tex->GetBaseMipmapLevel()))
+ if (!tex->IsMipmapRangeValid())
+ {
+ return ErrorInvalidOperation("generateMipmap: Texture does not have a valid mipmap range.");
+ }
+ if (!tex->HasImageInfoAt(imageTarget, tex->EffectiveBaseMipmapLevel()))
{
return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
}
diff --git a/dom/canvas/WebGLContextUtils.cpp b/dom/canvas/WebGLContextUtils.cpp
index 55b93c1b2e7e..e32cfb2b03a9 100644
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -867,6 +867,7 @@ InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims)
}
case WebGLTexDimensions::Tex3D:
switch (func) {
+ case WebGLTexImageFunc::TexImage: return "texImage3D";
case WebGLTexImageFunc::TexSubImage: return "texSubImage3D";
case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp
index e14bbc4d7c7a..1f5e6226b629 100644
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -14,6 +14,7 @@
#include "WebGLTexelConversions.h"
#include
+#include "mozilla/MathAlgorithms.h"
using namespace mozilla;
@@ -64,36 +65,50 @@ WebGLTexture::MemoryUsage() const {
return 0;
size_t result = 0;
for(size_t face = 0; face < mFacesCount; face++) {
- for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
- result += ImageInfoAtFace(face, level).MemoryUsage();
- }
+ for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
+ result += ImageInfoAtFace(face, level).MemoryUsage();
+ }
return result;
}
+static inline size_t
+MipmapLevelsForSize(const WebGLTexture::ImageInfo &info)
+{
+ GLsizei size = std::max(std::max(info.Width(), info.Height()), info.Depth());
+
+ // Find floor(log2(size)). (ES 3.0.4, 3.8 - Mipmapping).
+ return mozilla::FloorLog2(size);
+}
+
bool
WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const
{
+ // We could not have generated a mipmap if the base image wasn't defined.
if (mHaveGeneratedMipmap)
return true;
- if (GetMaxMipmapLevel() < GetBaseMipmapLevel())
+ if (!IsMipmapRangeValid())
return false;
// We want a copy here so we can modify it temporarily.
- ImageInfo expected = ImageInfoAt(texImageTarget, GetBaseMipmapLevel());
+ ImageInfo expected = ImageInfoAt(texImageTarget, EffectiveBaseMipmapLevel());
+ if (!expected.IsPositive())
+ return false;
- // checks if custom level>0 images are all defined up to the highest level defined
- // and have the expected dimensions
- for (size_t level = GetBaseMipmapLevel(); level <= GetMaxMipmapLevel(); ++level) {
+ // If Level{max} is > mMaxLevelWithCustomImages, then check if we are
+ // missing any image levels.
+ if (mMaxMipmapLevel > mMaxLevelWithCustomImages) {
+ if (MipmapLevelsForSize(expected) > mMaxLevelWithCustomImages)
+ return false;
+ }
+
+ // Checks if custom images are all defined up to the highest level and
+ // have the expected dimensions.
+ for (size_t level = EffectiveBaseMipmapLevel(); level <= EffectiveMaxMipmapLevel(); ++level) {
const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
if (actual != expected)
return false;
- // Check the raw value here, not the clamped one, since we don't want
- // to terminate early if there aren't enough levels defined.
- if (level == mMaxMipmapLevel)
- return true;
-
expected.mWidth = std::max(1, expected.mWidth / 2);
expected.mHeight = std::max(1, expected.mHeight / 2);
expected.mDepth = std::max(1, expected.mDepth / 2);
@@ -108,8 +123,7 @@ WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImage
}
}
- // if we're here, we've exhausted all levels without finding a 1x1 image
- return false;
+ return true;
}
void
@@ -177,25 +191,19 @@ WebGLTexture::SetGeneratedMipmap() {
void
WebGLTexture::SetCustomMipmap() {
if (mHaveGeneratedMipmap) {
- // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
- // we need to compute now all the mipmap image info.
+ if (!IsMipmapRangeValid())
+ return;
- // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
- // and are power-of-two.
- ImageInfo imageInfo = ImageInfoAtFace(0, GetBaseMipmapLevel());
+ // If we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
+ // we now need to compute all the mipmap image info.
+ ImageInfo imageInfo = ImageInfoAtFace(0, EffectiveBaseMipmapLevel());
NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(),
"this texture is NPOT, so how could GenerateMipmap() ever accept it?");
- GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
+ size_t maxLevel = MipmapLevelsForSize(imageInfo);
+ EnsureMaxLevelWithCustomImagesAtLeast(EffectiveBaseMipmapLevel() + maxLevel);
- // Find floor(log2(size)). (ES 3.0.4, 3.8 - Mipmapping).
- size_t maxLevel = 0;
- for (GLsizei n = size; n > 1; n >>= 1)
- ++maxLevel;
-
- EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
-
- for (size_t level = GetBaseMipmapLevel() + 1; level <= GetMaxMipmapLevel(); ++level) {
+ for (size_t level = EffectiveBaseMipmapLevel() + 1; level <= EffectiveMaxMipmapLevel(); ++level) {
imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
@@ -219,11 +227,6 @@ bool
WebGLTexture::IsMipmapComplete() const {
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D ||
mTarget == LOCAL_GL_TEXTURE_3D);
-
- if (!ImageInfoAtFace(0, GetBaseMipmapLevel()).IsPositive())
- return false;
- if (mHaveGeneratedMipmap)
- return true;
return DoesMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
}
@@ -249,6 +252,17 @@ WebGLTexture::IsMipmapCubeComplete() const {
return true;
}
+bool
+WebGLTexture::IsMipmapRangeValid() const
+{
+ // In ES3, if a texture is immutable, the mipmap levels are clamped.
+ if (IsImmutable())
+ return true;
+ if (mBaseMipmapLevel > std::min(mMaxLevelWithCustomImages, mMaxMipmapLevel))
+ return false;
+ return true;
+}
+
WebGLTextureFakeBlackStatus
WebGLTexture::ResolvedFakeBlackStatus() {
if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) {
@@ -256,10 +270,14 @@ WebGLTexture::ResolvedFakeBlackStatus() {
}
// Determine if the texture needs to be faked as a black texture.
- // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
-
+ // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec, and 3.8.13 in
+ // the OpenGL ES 3.0.4 spec.
+ if (!IsMipmapRangeValid()) {
+ mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
+ return mFakeBlackStatus;
+ }
for (size_t face = 0; face < mFacesCount; ++face) {
- if (ImageInfoAtFace(face, GetBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
+ if (ImageInfoAtFace(face, EffectiveBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
// In case of undefined texture image, we don't print any message because this is a very common
// and often legitimate case (asynchronous texture loading).
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h
index 134f25094677..0769fbf68206 100644
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -17,6 +17,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/Assertions.h"
#include
+#include "nsAlgorithm.h"
namespace mozilla {
@@ -286,16 +287,22 @@ public:
bool IsImmutable() const { return mImmutable; }
void SetImmutable() { mImmutable = true; }
- void SetBaseMipmapLevel(unsigned level) { mBaseMipmapLevel = level; }
- void SetMaxMipmapLevel(unsigned level) { mMaxMipmapLevel = level; }
- size_t GetBaseMipmapLevel() const {
- // Clamp to [0, levels - 1]
- return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages);
+ void SetBaseMipmapLevel(size_t level) { mBaseMipmapLevel = level; }
+ void SetMaxMipmapLevel(size_t level) { mMaxMipmapLevel = level; }
+
+ // Clamping (from ES 3.0.4, section 3.8 - Texturing). When not immutable,
+ // the ranges must be guarded.
+ size_t EffectiveBaseMipmapLevel() const {
+ if (IsImmutable())
+ return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages);
+ return mBaseMipmapLevel;
}
- size_t GetMaxMipmapLevel() const {
- // Clamp to [base, levels - 1]
+ size_t EffectiveMaxMipmapLevel() const {
+ if (IsImmutable())
+ return mozilla::clamped(mMaxMipmapLevel, EffectiveBaseMipmapLevel(), mMaxLevelWithCustomImages);
return std::min(mMaxMipmapLevel, mMaxLevelWithCustomImages);
}
+ bool IsMipmapRangeValid() const;
size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages; }
diff --git a/dom/json/nsJSON.cpp b/dom/json/nsJSON.cpp
index b54814688427..ae3999333073 100644
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -22,6 +22,7 @@
#include "nsCRTGlue.h"
#include "nsAutoPtr.h"
#include "nsIScriptSecurityManager.h"
+#include "nsNullPrincipal.h"
#include "mozilla/Maybe.h"
#include
@@ -409,9 +410,19 @@ nsJSON::DecodeInternal(JSContext* cx,
return NS_ERROR_OUT_OF_MEMORY;
}
- nsresult rv =
- NS_NewInputStreamChannel(getter_AddRefs(jsonChannel), mURI, aStream,
- NS_LITERAL_CSTRING("application/json"));
+ nsresult rv;
+ nsCOMPtr nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = NS_NewInputStreamChannel(getter_AddRefs(jsonChannel),
+ mURI,
+ aStream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
+ NS_LITERAL_CSTRING("application/json"));
+
if (!jsonChannel || NS_FAILED(rv))
return NS_ERROR_FAILURE;
diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp
index 06ad830f7a63..2d3b56c65688 100644
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -36,6 +36,7 @@
#include "nsIContentViewer.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
+#include "nsNullPrincipal.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
#include "nsIScriptChannel.h"
@@ -427,9 +428,18 @@ nsresult nsJSChannel::Init(nsIURI *aURI)
// and the underlying Input Stream will not be created...
nsCOMPtr channel;
+ nsCOMPtr nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// If the resultant script evaluation actually does return a value, we
// treat it as html.
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, mIOThunk,
+ rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
+ aURI,
+ mIOThunk,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING("text/html"));
if (NS_FAILED(rv)) return rv;
diff --git a/dom/webidl/MediaKeySession.webidl b/dom/webidl/MediaKeySession.webidl
index c9ea12402099..4a1274ad50d7 100644
--- a/dom/webidl/MediaKeySession.webidl
+++ b/dom/webidl/MediaKeySession.webidl
@@ -21,7 +21,6 @@ interface MediaKeySession : EventTarget {
readonly attribute unrestricted double expiration;
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
readonly attribute Promise closed;
[NewObject, Throws]
@@ -31,15 +30,12 @@ interface MediaKeySession : EventTarget {
Promise load(DOMString sessionId);
// session operations
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise update((ArrayBufferView or ArrayBuffer) response);
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise close();
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise remove();
diff --git a/dom/webidl/MediaKeys.webidl b/dom/webidl/MediaKeys.webidl
index 4187ca0f11d2..7467ed68b7f0 100644
--- a/dom/webidl/MediaKeys.webidl
+++ b/dom/webidl/MediaKeys.webidl
@@ -20,7 +20,6 @@ interface MediaKeys {
[NewObject, Throws]
MediaKeySession createSession(optional SessionType sessionType = "temporary");
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise setServerCertificate((ArrayBufferView or ArrayBuffer) serverCertificate);
diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl
index 4784f83224f3..6b950dcfe462 100644
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -342,6 +342,11 @@ interface WebGL2RenderingContext : WebGLRenderingContext
void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth);
+ [Throws]
+ void texImage3D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format,
+ GLenum type, ArrayBufferView? pixels);
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
ArrayBufferView? pixels);
diff --git a/editor/libeditor/nsHTMLEditorEventListener.cpp b/editor/libeditor/nsHTMLEditorEventListener.cpp
index e05caa14c331..68c777cab81d 100644
--- a/editor/libeditor/nsHTMLEditorEventListener.cpp
+++ b/editor/libeditor/nsHTMLEditorEventListener.cpp
@@ -72,6 +72,11 @@ nsresult
nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
nsHTMLEditor* htmlEditor = GetHTMLEditor();
+ // Contenteditable should disregard mousedowns outside it.
+ // IsAcceptableInputEvent() checks it for a mouse event.
+ if (!htmlEditor->IsAcceptableInputEvent(aMouseEvent)) {
+ return NS_OK;
+ }
// Detect only "context menu" click
// XXX This should be easier to do!
@@ -93,11 +98,6 @@ nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
nsCOMPtr element = do_QueryInterface(target);
- // Contenteditable should disregard mousedowns outside it
- if (element && !htmlEditor->IsDescendantOfEditorRoot(element)) {
- return NS_OK;
- }
-
if (isContextClick || (buttonNumber == 0 && clickCount == 2)) {
nsCOMPtr selection;
mEditor->GetSelection(getter_AddRefs(selection));
diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp
index 6b483ffa57b5..105039ec61ce 100644
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -17,6 +17,7 @@
#include "nsIStandardURL.h"
#include "nsMimeTypes.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
#include "mozilla/Monitor.h"
#include
#include
@@ -1062,11 +1063,18 @@ nsGIOProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **aResult)
}
else
{
+ nsCOMPtr nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// start out assuming an unknown content-type. we'll set the content-type
// to something better once we open the URI.
rv = NS_NewInputStreamChannel(aResult,
aURI,
stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
if (NS_SUCCEEDED(rv))
stream->SetChannel(*aResult);
diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp
index f18245c85d1e..820484112f2b 100644
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -548,11 +548,12 @@ Factory::SetDirect3D10Device(ID3D10Device1 *aDevice)
ID3D10Device1*
Factory::GetDirect3D10Device()
-
{
#ifdef DEBUG
- UINT mode = mD3D10Device->GetExceptionMode();
- MOZ_ASSERT(0 == mode);
+ if (mD3D10Device) {
+ UINT mode = mD3D10Device->GetExceptionMode();
+ MOZ_ASSERT(0 == mode);
+ }
#endif
return mD3D10Device;
}
diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
index 6beb97fd2477..da63a55ca4b3 100644
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -17,8 +17,3 @@ endif
include $(topsrcdir)/config/rules.mk
-# We have to filter out -pedantic, because of
-# comma-at-end-of-enumerator list failures. We can try to get this fixed
-# upstream at some point.
-CXXFLAGS := $(filter-out -pedantic,$(CXXFLAGS))
-CFLAGS := $(filter-out -pedantic,$(CFLAGS))
diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp
index 7d517e522a6b..ca673de0af1e 100644
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1253,7 +1253,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
if (IsSupported(GLFeature::texture_3D)) {
SymLoadStruct coreSymbols[] = {
- // TexImage3D is not required for WebGL2 so not queried here.
+ { (PRFuncPtr*) &mSymbols.fTexImage3D, { "TexImage3D", nullptr } },
{ (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3D", nullptr } },
END_SYMBOLS
};
diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h
index 3e386faa8faf..16827ee141e2 100644
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -3132,6 +3132,21 @@ public:
// -----------------------------------------------------------------------------
// 3D Textures
+ void fTexImage3D(GLenum target, GLint level,
+ GLint internalFormat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const GLvoid * data)
+ {
+ BEFORE_GL_CALL;
+ ASSERT_SYMBOL_PRESENT(fTexImage3D);
+ mSymbols.fTexImage3D(target, level, internalFormat,
+ width, height, depth,
+ border, format, type,
+ data);
+ AFTER_GL_CALL;
+ }
+
void fTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const GLvoid* pixels)
diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h
index c4839a35440d..d02377f2e64f 100644
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -642,6 +642,12 @@ struct GLContextSymbols
PFNGLGETFRAGDATALOCATIONPROC fGetFragDataLocation;
// 3D Textures
+ typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level,
+ GLenum internalFormat,
+ GLenum width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const GLvoid* pixels);
+ PFNGLTEXIMAGE3DPROC fTexImage3D;
typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format,
diff --git a/gfx/thebes/gfxSVGGlyphs.cpp b/gfx/thebes/gfxSVGGlyphs.cpp
index 47f264b28bef..19de263fbc7b 100644
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -369,17 +369,16 @@ gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen)
}
nsCOMPtr channel;
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel), uri, nullptr /* stream */,
- SVG_CONTENT_TYPE, UTF8_CHARSET);
+ rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
+ uri,
+ nullptr, //aStream
+ principal,
+ nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER,
+ SVG_CONTENT_TYPE,
+ UTF8_CHARSET);
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr loadInfo =
- new LoadInfo(principal,
- nullptr,
- nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER);
- channel->SetLoadInfo(loadInfo);
-
// Set this early because various decisions during page-load depend on it.
document->SetIsBeingUsedAsImage();
document->SetReadyStateInternal(nsIDocument::READYSTATE_UNINITIALIZED);
diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp
index 583821cc4b81..4e4aa5225686 100644
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -413,7 +413,7 @@ gfxUserFontEntry::LoadNextSrc()
mItalic);
mFontSet->SetLocalRulesUsed();
if (fe) {
- LOG(("fontset (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
+ LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
mFontSet, mSrcIndex,
NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
NS_ConvertUTF16toUTF8(mFamilyName).get(),
@@ -430,7 +430,7 @@ gfxUserFontEntry::LoadNextSrc()
SetLoadState(STATUS_LOADED);
return;
} else {
- LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
+ LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
mFontSet, mSrcIndex,
NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
@@ -647,7 +647,7 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
nsAutoCString fontURI;
mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
- this, mSrcIndex, fontURI.get(),
+ mFontSet, mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(mFamilyName).get(),
uint32_t(mFontSet->mGeneration)));
}
@@ -662,7 +662,7 @@ gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
" error making platform font\n",
- this, mSrcIndex, fontURI.get(),
+ mFontSet, mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
#endif
diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h
index b2a5bfa8da7a..07e0d2132702 100644
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -467,6 +467,10 @@ public:
mLocalRulesUsed = true;
}
+#ifdef PR_LOGGING
+ static PRLogModuleInfo* GetUserFontsLog();
+#endif
+
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~gfxUserFontSet();
@@ -512,8 +516,6 @@ protected:
// true when local names have been looked up, false otherwise
bool mLocalRulesUsed;
-
- static PRLogModuleInfo* GetUserFontsLog();
};
// acts a placeholder until the real font is downloaded
diff --git a/image/decoders/icon/android/nsIconChannel.cpp b/image/decoders/icon/android/nsIconChannel.cpp
index 074450366646..6030a66e0e07 100644
--- a/image/decoders/icon/android/nsIconChannel.cpp
+++ b/image/decoders/icon/android/nsIconChannel.cpp
@@ -12,6 +12,7 @@
#include "nsIconChannel.h"
#include "nsIStringStream.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
NS_IMPL_ISUPPORTS(nsIconChannel,
nsIRequest,
@@ -102,7 +103,16 @@ moz_icon_to_channel(nsIURI *aURI, const nsACString& aFileExt, uint32_t aIconSize
rv = stream->AdoptData((char*)buf, buf_size);
NS_ENSURE_SUCCESS(rv, rv);
- return NS_NewInputStreamChannel(aChannel, aURI, stream,
+ nsCOMPtr nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewInputStreamChannel(aChannel,
+ aURI,
+ stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
diff --git a/image/decoders/icon/gtk/nsIconChannel.cpp b/image/decoders/icon/gtk/nsIconChannel.cpp
index 03e830880922..b7b96e74a64c 100644
--- a/image/decoders/icon/gtk/nsIconChannel.cpp
+++ b/image/decoders/icon/gtk/nsIconChannel.cpp
@@ -33,6 +33,7 @@ extern "C" {
#include "nsIStringBundle.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
#include "nsIURL.h"
#include "prlink.h"
@@ -137,9 +138,17 @@ moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI *aURI,
MOZ_ASSERT(NS_SUCCEEDED(rv));
NS_ENSURE_SUCCESS(rv, rv);
- rv = NS_NewInputStreamChannel(aChannel, aURI, stream,
- NS_LITERAL_CSTRING(IMAGE_ICON_MS));
- return rv;
+ nsCOMPtr nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewInputStreamChannel(aChannel,
+ aURI,
+ stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
+ NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
static GtkWidget *gProtoWindow = nullptr;
diff --git a/image/decoders/icon/qt/nsIconChannel.cpp b/image/decoders/icon/qt/nsIconChannel.cpp
index 46375a8b53e3..84f7bb95f5eb 100644
--- a/image/decoders/icon/qt/nsIconChannel.cpp
+++ b/image/decoders/icon/qt/nsIconChannel.cpp
@@ -16,6 +16,7 @@
#include "nsIStringBundle.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
#include "nsIURL.h"
#include "nsIconChannel.h"
@@ -83,7 +84,16 @@ moz_qicon_to_channel(QImage *image, nsIURI *aURI,
rv = stream->AdoptData((char*)buf, buf_size);
NS_ENSURE_SUCCESS(rv, rv);
- return NS_NewInputStreamChannel(aChannel, aURI, stream,
+ nsCOMPtr nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewInputStreamChannel(aChannel,
+ aURI,
+ stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
diff --git a/ipc/chromium/src/base/message_loop.cc b/ipc/chromium/src/base/message_loop.cc
index b8e7138ce11f..27c1e3625a87 100644
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -125,6 +125,9 @@ MessageLoop::MessageLoop(Type type)
pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads();
return;
#endif
+ default:
+ // Create one of Chromium's standard MessageLoop types below.
+ break;
}
#if defined(OS_WIN)
diff --git a/js/ipc/JavaScriptBase.h b/js/ipc/JavaScriptBase.h
index 4ff69ab984ad..a7cf7ff46ee2 100644
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -102,8 +102,8 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
}
bool RecvGetPropertyKeys(const uint64_t &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray *names) {
- return Answer::RecvGetPropertyKeys(ObjectId::deserialize(objId), flags, rs, names);
+ ReturnStatus *rs, nsTArray *ids) {
+ return Answer::RecvGetPropertyKeys(ObjectId::deserialize(objId), flags, rs, ids);
}
bool RecvInstanceOf(const uint64_t &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
@@ -200,8 +200,8 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
}
bool SendGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray *names) {
- return Base::SendGetPropertyKeys(objId.serialize(), flags, rs, names);
+ ReturnStatus *rs, nsTArray *ids) {
+ return Base::SendGetPropertyKeys(objId.serialize(), flags, rs, ids);
}
bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp
index cff04a719612..38a73cb470e4 100644
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -440,7 +440,8 @@ JavaScriptShared::toSymbolVariant(JSContext *cx, JS::Symbol *symArg, SymbolVaria
*symVarp = RegisteredSymbol(autoStr);
return true;
}
- MOZ_CRASH("unique symbols not yet implemented");
+
+ JS_ReportError(cx, "unique symbol can't be used with CPOW");
return false;
}
diff --git a/js/ipc/PJavaScript.ipdl b/js/ipc/PJavaScript.ipdl
index b17a02ad499d..d8d0254e97e6 100644
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -42,7 +42,7 @@ both:
prio(high) sync ClassName(uint64_t objId) returns (nsString name);
prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
- prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
+ prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids);
prio(high) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
prio(high) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
diff --git a/js/ipc/WrapperAnswer.cpp b/js/ipc/WrapperAnswer.cpp
index b63013e70b9c..ce8a7eaf4f58 100644
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -580,7 +580,7 @@ WrapperAnswer::RecvRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
bool
WrapperAnswer::RecvGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray *names)
+ ReturnStatus *rs, nsTArray *ids)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
@@ -598,11 +598,11 @@ WrapperAnswer::RecvGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
return fail(cx, rs);
for (size_t i = 0; i < props.length(); i++) {
- nsString name;
- if (!convertIdToGeckoString(cx, props[i], &name))
+ JSIDVariant id;
+ if (!toJSIDVariant(cx, props[i], &id))
return fail(cx, rs);
- names->AppendElement(name);
+ ids->AppendElement(id);
}
return ok(rs);
diff --git a/js/ipc/WrapperAnswer.h b/js/ipc/WrapperAnswer.h
index fc3b481f9532..08171528de21 100644
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -55,7 +55,7 @@ class WrapperAnswer : public virtual JavaScriptShared
bool RecvRegExpToShared(const ObjectId &objId, ReturnStatus *rs, nsString *source, uint32_t *flags);
bool RecvGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray *names);
+ ReturnStatus *rs, nsTArray *ids);
bool RecvInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof);
bool RecvDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp
index 31abb5ce2a3d..fb5767420acf 100644
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -63,9 +63,6 @@ class CPOWProxyHandler : public BaseProxyHandler
return false;
}
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
@@ -74,18 +71,21 @@ class CPOWProxyHandler : public BaseProxyHandler
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
-
+ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
-
- virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle desc) const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy,
MutableHandleValue v, bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue,
@@ -232,7 +232,7 @@ CPOWProxyHandler::ownPropertyKeys(JSContext *cx, HandleObject proxy,
bool
WrapperOwner::ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
- return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
+ return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
}
bool
@@ -463,13 +463,14 @@ WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiv
}
bool
-CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const
{
- FORWARD(keys, (cx, proxy, props));
+ FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props));
}
bool
-WrapperOwner::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+WrapperOwner::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
}
@@ -776,8 +777,8 @@ WrapperOwner::getPropertyKeys(JSContext *cx, HandleObject proxy, uint32_t flags,
ObjectId objId = idOf(proxy);
ReturnStatus status;
- InfallibleTArray names;
- if (!SendGetPropertyKeys(objId, flags, &status, &names))
+ InfallibleTArray ids;
+ if (!SendGetPropertyKeys(objId, flags, &status, &ids))
return ipcfail(cx);
LOG_STACK();
@@ -785,11 +786,11 @@ WrapperOwner::getPropertyKeys(JSContext *cx, HandleObject proxy, uint32_t flags,
if (!ok(cx, status))
return false;
- for (size_t i = 0; i < names.Length(); i++) {
- RootedId name(cx);
- if (!convertGeckoStringToId(cx, names[i], &name))
+ for (size_t i = 0; i < ids.Length(); i++) {
+ RootedId id(cx);
+ if (!fromJSIDVariant(cx, ids[i], &id))
return false;
- if (!props.append(name))
+ if (!props.append(id))
return false;
}
diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h
index 215043dfc072..a626ca1832a1 100644
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -31,11 +31,8 @@ class WrapperOwner : public virtual JavaScriptShared
explicit WrapperOwner(JSRuntime *rt);
bool init();
- // Fundamental proxy traps. These are required.
+ // Standard internal methods.
// (The traps should be in the same order like js/src/jsproxy.h)
- bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
- bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
- JS::MutableHandle desc);
bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle desc);
bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
@@ -43,25 +40,27 @@ class WrapperOwner : public virtual JavaScriptShared
bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
-
- // Derived proxy traps. Implementing these is useful for perfomance.
+ bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
+ bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
- bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, JS::MutableHandleValue vp);
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp);
- bool keys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
- // We use "iterate" provided by the base class here.
-
- // SpiderMonkey Extensions.
- bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
- bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
bool construct);
+
+ // SpiderMonkey extensions.
+ bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+ JS::MutableHandle desc);
+ bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
+ bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy,
+ JS::AutoIdVector &props);
+ // We use "iterate" provided by the base class here.
bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
const char* className(JSContext *cx, JS::HandleObject proxy);
+ bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
bool isCallable(JSObject *obj);
bool isConstructor(JSObject *obj);
@@ -146,7 +145,7 @@ class WrapperOwner : public virtual JavaScriptShared
uint32_t *flags) = 0;
virtual bool SendGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray *names) = 0;
+ ReturnStatus *rs, nsTArray *ids) = 0;
virtual bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) = 0;
virtual bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index 372bcbd88f06..ada06a5ab413 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -315,6 +315,7 @@ selfhosting_srcs := \
$(srcdir)/builtin/Array.js \
$(srcdir)/builtin/Date.js \
$(srcdir)/builtin/Error.js \
+ $(srcdir)/builtin/Generator.js \
$(srcdir)/builtin/Intl.js \
$(srcdir)/builtin/IntlData.js \
$(srcdir)/builtin/Iterator.js \
diff --git a/js/src/builtin/Generator.js b/js/src/builtin/Generator.js
new file mode 100644
index 000000000000..6bea65305fa8
--- /dev/null
+++ b/js/src/builtin/Generator.js
@@ -0,0 +1,104 @@
+/* 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 StarGeneratorNext(val) {
+ if (!IsObject(this) || !IsStarGeneratorObject(this))
+ return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorNext");
+
+ if (StarGeneratorObjectIsClosed(this))
+ return { value: undefined, done: true };
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'next');
+ } catch (e) {
+ if (!StarGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+function StarGeneratorThrow(val) {
+ if (!IsObject(this) || !IsStarGeneratorObject(this))
+ return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorThrow");
+
+ if (StarGeneratorObjectIsClosed(this))
+ throw val;
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'throw');
+ } catch (e) {
+ if (!StarGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+function LegacyGeneratorNext(val) {
+ if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+ return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorNext");
+
+ if (LegacyGeneratorObjectIsClosed(this))
+ ThrowStopIteration();
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'next');
+ } catch(e) {
+ if (!LegacyGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+function LegacyGeneratorThrow(val) {
+ if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+ return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorThrow");
+
+ if (LegacyGeneratorObjectIsClosed(this))
+ throw val;
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'throw');
+ } catch(e) {
+ if (!LegacyGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+// Called by js::CloseIterator.
+function LegacyGeneratorCloseInternal() {
+ assert(IsObject(this), "Not an object: " + ToString(this));
+ assert(IsLegacyGeneratorObject(this), "Not a legacy generator object: " + ToString(this));
+ assert(!LegacyGeneratorObjectIsClosed(this), "Already closed: " + ToString(this));
+ assert(!CloseNewbornLegacyGeneratorObject(this), "Newborn: " + ToString(this));
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ resumeGenerator(this, undefined, 'close');
+ if (!LegacyGeneratorObjectIsClosed(this))
+ CloseClosingLegacyGeneratorObject(this);
+}
+
+function LegacyGeneratorClose() {
+ if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+ return callFunction(CallLegacyGeneratorMethodIfWrapped, this, "LegacyGeneratorClose");
+
+ if (LegacyGeneratorObjectIsClosed(this) || CloseNewbornLegacyGeneratorObject(this))
+ return;
+
+ callFunction(LegacyGeneratorCloseInternal, this);
+}
diff --git a/js/src/configure.in b/js/src/configure.in
index 7c537c3df566..a9e758e11522 100644
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1294,7 +1294,6 @@ if test "$GNU_CXX"; then
# -Wwrite-strings - catches non-const char* pointers to string literals
#
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
- _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wignored-qualifiers"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
@@ -1303,6 +1302,7 @@ if test "$GNU_CXX"; then
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=comment"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=empty-body"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=ignored-qualifiers"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=overloaded-virtual"
diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp
index bdcdb28e89ea..82c47b7a0b49 100644
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2625,8 +2625,8 @@ ImplicitConvert(JSContext* cx,
if (val.isObject() && !sourceData) {
// Enumerate the properties of the object; if they match the struct
// specification, convert the fields.
- RootedObject iter(cx, JS_NewPropertyIterator(cx, valObj));
- if (!iter)
+ AutoIdArray props(cx, JS_Enumerate(cx, valObj));
+ if (!props)
return false;
// Convert into an intermediate, in case of failure.
@@ -2637,13 +2637,15 @@ ImplicitConvert(JSContext* cx,
return false;
}
+ const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
+ if (props.length() != fields->count()) {
+ JS_ReportError(cx, "missing fields");
+ return false;
+ }
+
RootedId id(cx);
- size_t i = 0;
- while (1) {
- if (!JS_NextProperty(cx, iter, &id))
- return false;
- if (JSID_IS_VOID(id))
- break;
+ for (size_t i = 0; i < props.length(); ++i) {
+ id = props[i];
if (!JSID_IS_STRING(id)) {
JS_ReportError(cx, "property name is not a string");
@@ -2663,14 +2665,6 @@ ImplicitConvert(JSContext* cx,
char* fieldData = intermediate.get() + field->mOffset;
if (!ImplicitConvert(cx, prop, field->mType, fieldData, false, nullptr))
return false;
-
- ++i;
- }
-
- const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
- if (i != fields->count()) {
- JS_ReportError(cx, "missing fields");
- return false;
}
memcpy(buffer, intermediate.get(), structSize);
@@ -4705,33 +4699,23 @@ ExtractStructField(JSContext* cx, jsval val, MutableHandleObject typeObj)
return nullptr;
}
- RootedObject obj(cx, val.toObjectOrNull());
- RootedObject iter(cx, JS_NewPropertyIterator(cx, obj));
- if (!iter)
+ RootedObject obj(cx, &val.toObject());
+ AutoIdArray props(cx, JS_Enumerate(cx, obj));
+ if (!props)
return nullptr;
- RootedId nameid(cx);
- if (!JS_NextProperty(cx, iter, &nameid))
- return nullptr;
- if (JSID_IS_VOID(nameid)) {
- JS_ReportError(cx, "struct field descriptors require a valid name and type");
- return nullptr;
- }
-
- if (!JSID_IS_STRING(nameid)) {
- JS_ReportError(cx, "struct field descriptors require a valid name and type");
- return nullptr;
- }
-
// make sure we have one, and only one, property
- RootedId id(cx);
- if (!JS_NextProperty(cx, iter, &id))
- return nullptr;
- if (!JSID_IS_VOID(id)) {
+ if (props.length() != 1) {
JS_ReportError(cx, "struct field descriptors must contain one property");
return nullptr;
}
+ RootedId nameid(cx, props[0]);
+ if (!JSID_IS_STRING(nameid)) {
+ JS_ReportError(cx, "struct field descriptors require a valid name and type");
+ return nullptr;
+ }
+
RootedValue propVal(cx);
if (!JS_GetPropertyById(cx, obj, nameid, &propVal))
return nullptr;
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 065c193e62cb..70e9b45515cb 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -31,6 +31,7 @@
#include "frontend/Parser.h"
#include "frontend/TokenStream.h"
#include "vm/Debugger.h"
+#include "vm/GeneratorObject.h"
#include "vm/Stack.h"
#include "jsatominlines.h"
@@ -1989,10 +1990,10 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
default:
/*
- * All of PNK_INC, PNK_DEC, PNK_THROW, PNK_YIELD, and PNK_YIELD_STAR
- * have direct effects. Of the remaining unary-arity node types, we
- * can't easily prove that the operand never denotes an object with
- * a toString or valueOf method.
+ * All of PNK_INC, PNK_DEC and PNK_THROW have direct effects. Of
+ * the remaining unary-arity node types, we can't easily prove that
+ * the operand never denotes an object with a toString or valueOf
+ * method.
*/
*answer = true;
return true;
@@ -2973,13 +2974,6 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
bce->switchToMain();
}
- if (funbox->isGenerator()) {
- bce->switchToProlog();
- if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
- return false;
- bce->switchToMain();
- }
-
/*
* Emit a prologue for run-once scripts which will deoptimize JIT code if
* the script ends up running multiple times via foo.caller related
@@ -2996,18 +2990,27 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
if (!EmitTree(cx, bce, body))
return false;
- // If we fall off the end of an ES6 generator, return a boxed iterator
- // result object of the form { value: undefined, done: true }.
- if (bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isStarGenerator()) {
- if (!EmitPrepareIteratorResult(cx, bce))
+ // If we fall off the end of a generator, do a final yield.
+ if (bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isGenerator()) {
+ if (bce->sc->asFunctionBox()->isStarGenerator() && !EmitPrepareIteratorResult(cx, bce))
return false;
+
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
return false;
- if (!EmitFinishIteratorResult(cx, bce, true))
+
+ if (bce->sc->asFunctionBox()->isStarGenerator() && !EmitFinishIteratorResult(cx, bce, true))
+ return false;
+
+ ScopeCoordinate sc;
+ // We know that .generator is on the top scope chain node, as we are
+ // at the function end.
+ sc.setHops(0);
+ MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc));
+ if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce))
return false;
// No need to check for finally blocks, etc as in EmitReturn.
- if (Emit1(cx, bce, JSOP_RETURN) < 0)
+ if (Emit1(cx, bce, JSOP_FINALYIELD) < 0)
return false;
}
@@ -5463,15 +5466,26 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
*/
ptrdiff_t top = bce->offset();
- if (Emit1(cx, bce, JSOP_RETURN) < 0)
- return false;
+ bool isGenerator = bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isGenerator();
+ if (Emit1(cx, bce, isGenerator ? JSOP_SETRVAL : JSOP_RETURN) < 0)
+ return false;
NonLocalExitScope nle(cx, bce);
if (!nle.prepareForNonLocalJump(nullptr))
return false;
- if (top + static_cast(JSOP_RETURN_LENGTH) != bce->offset()) {
+ if (isGenerator) {
+ ScopeCoordinate sc;
+ // We know that .generator is on the top scope chain node, as we just
+ // exited nested scopes.
+ sc.setHops(0);
+ MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc));
+ if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce))
+ return false;
+ if (Emit1(cx, bce, JSOP_FINALYIELDRVAL) < 0)
+ return false;
+ } else if (top + static_cast(JSOP_RETURN_LENGTH) != bce->offset()) {
bce->code()[top] = JSOP_SETRVAL;
if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
return false;
@@ -5481,7 +5495,41 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
static bool
-EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
+EmitYield(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
+{
+ MOZ_ASSERT(bce->sc->isFunctionBox());
+
+ if (pn->getOp() == JSOP_YIELD) {
+ if (bce->sc->asFunctionBox()->isStarGenerator()) {
+ if (!EmitPrepareIteratorResult(cx, bce))
+ return false;
+ }
+ if (pn->pn_left) {
+ if (!EmitTree(cx, bce, pn->pn_left))
+ return false;
+ } else {
+ if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
+ return false;
+ }
+ if (bce->sc->asFunctionBox()->isStarGenerator()) {
+ if (!EmitFinishIteratorResult(cx, bce, false))
+ return false;
+ }
+ } else {
+ MOZ_ASSERT(pn->getOp() == JSOP_INITIALYIELD);
+ }
+
+ if (!EmitTree(cx, bce, pn->pn_right))
+ return false;
+
+ if (Emit1(cx, bce, pn->getOp()) < 0)
+ return false;
+
+ return true;
+}
+
+static bool
+EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, ParseNode *gen)
{
MOZ_ASSERT(bce->sc->isFunctionBox());
MOZ_ASSERT(bce->sc->asFunctionBox()->isStarGenerator());
@@ -5500,12 +5548,13 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
return false;
CheckTypeSet(cx, bce, JSOP_CALL);
- int depth = bce->stackDepth;
- MOZ_ASSERT(depth >= 1);
-
// Initial send value is undefined.
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RECEIVED
return false;
+
+ int depth = bce->stackDepth;
+ MOZ_ASSERT(depth >= 2);
+
ptrdiff_t initialSend = -1;
if (EmitBackPatchOp(cx, bce, &initialSend) < 0) // goto initialSend
return false;
@@ -5514,17 +5563,21 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
StmtInfoBCE stmtInfo(cx);
PushStatementBCE(bce, &stmtInfo, STMT_TRY, bce->offset());
ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_TRY);
+ ptrdiff_t tryStart = bce->offset(); // tryStart:
if (noteIndex < 0 || Emit1(cx, bce, JSOP_TRY) < 0)
return false;
- ptrdiff_t tryStart = bce->offset(); // tryStart:
- MOZ_ASSERT(bce->stackDepth == depth + 1);
+ MOZ_ASSERT(bce->stackDepth == depth);
+
+ // Load the generator object.
+ if (!EmitTree(cx, bce, gen)) // ITER RESULT GENOBJ
+ return false;
// Yield RESULT as-is, without re-boxing.
if (Emit1(cx, bce, JSOP_YIELD) < 0) // ITER RECEIVED
return false;
// Try epilogue.
- if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, bce->offset() - tryStart + JSOP_TRY_LENGTH))
+ if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, bce->offset() - tryStart))
return false;
ptrdiff_t subsequentSend = -1;
if (EmitBackPatchOp(cx, bce, &subsequentSend) < 0) // goto subsequentSend
@@ -5532,8 +5585,10 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
ptrdiff_t tryEnd = bce->offset(); // tryEnd:
// Catch location.
- // THROW? = 'throw' in ITER // ITER
- bce->stackDepth = (uint32_t) depth;
+ bce->stackDepth = uint32_t(depth); // ITER RESULT
+ if (Emit1(cx, bce, JSOP_POP) < 0) // ITER
+ return false;
+ // THROW? = 'throw' in ITER
if (Emit1(cx, bce, JSOP_EXCEPTION) < 0) // ITER EXCEPTION
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // EXCEPTION ITER
@@ -5557,7 +5612,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
SetJumpOffsetAt(bce, checkThrow); // delegate:
// RESULT = ITER.throw(EXCEPTION) // EXCEPTION ITER
- bce->stackDepth = (uint32_t) depth + 1;
+ bce->stackDepth = uint32_t(depth);
if (Emit1(cx, bce, JSOP_DUP) < 0) // EXCEPTION ITER ITER
return false;
if (Emit1(cx, bce, JSOP_DUP) < 0) // EXCEPTION ITER ITER ITER
@@ -5571,7 +5626,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
if (EmitCall(cx, bce, JSOP_CALL, 1, iter) < 0) // ITER RESULT
return false;
CheckTypeSet(cx, bce, JSOP_CALL);
- MOZ_ASSERT(bce->stackDepth == depth + 1);
+ MOZ_ASSERT(bce->stackDepth == depth);
ptrdiff_t checkResult = -1;
if (EmitBackPatchOp(cx, bce, &checkResult) < 0) // goto checkResult
return false;
@@ -5582,7 +5637,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
// This is a peace offering to ReconstructPCStack. See the note in EmitTry.
if (Emit1(cx, bce, JSOP_NOP) < 0)
return false;
- if (!bce->tryNoteList.append(JSTRY_CATCH, depth, tryStart, tryEnd))
+ if (!bce->tryNoteList.append(JSTRY_CATCH, depth, tryStart + JSOP_TRY_LENGTH, tryEnd))
return false;
// After the try/catch block: send the received value to the iterator.
@@ -5608,7 +5663,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
if (EmitCall(cx, bce, JSOP_CALL, 1, iter) < 0) // ITER RESULT
return false;
CheckTypeSet(cx, bce, JSOP_CALL);
- MOZ_ASSERT(bce->stackDepth == depth + 1);
+ MOZ_ASSERT(bce->stackDepth == depth);
if (!BackPatch(cx, bce, checkResult, bce->code().end(), JSOP_GOTO)) // checkResult:
return false;
@@ -5629,7 +5684,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // VALUE
return false;
- MOZ_ASSERT(bce->stackDepth == depth);
+ MOZ_ASSERT(bce->stackDepth == depth - 1);
return true;
}
@@ -5807,6 +5862,80 @@ EmitDelete(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
static bool
EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t count);
+static bool
+EmitSelfHostedCallFunction(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
+{
+ // Special-casing of callFunction to emit bytecode that directly
+ // invokes the callee with the correct |this| object and arguments.
+ // callFunction(fun, thisArg, arg0, arg1) thus becomes:
+ // - emit lookup for fun
+ // - emit lookup for thisArg
+ // - emit lookups for arg0, arg1
+ //
+ // argc is set to the amount of actually emitted args and the
+ // emitting of args below is disabled by setting emitArgs to false.
+ if (pn->pn_count < 3) {
+ bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "callFunction", "1", "s");
+ return false;
+ }
+
+ ParseNode *pn2 = pn->pn_head;
+ ParseNode *funNode = pn2->pn_next;
+ if (!EmitTree(cx, bce, funNode))
+ return false;
+
+ ParseNode *thisArg = funNode->pn_next;
+ if (!EmitTree(cx, bce, thisArg))
+ return false;
+
+ bool oldEmittingForInit = bce->emittingForInit;
+ bce->emittingForInit = false;
+
+ for (ParseNode *argpn = thisArg->pn_next; argpn; argpn = argpn->pn_next) {
+ if (!EmitTree(cx, bce, argpn))
+ return false;
+ }
+
+ bce->emittingForInit = oldEmittingForInit;
+
+ uint32_t argc = pn->pn_count - 3;
+ if (EmitCall(cx, bce, pn->getOp(), argc) < 0)
+ return false;
+
+ CheckTypeSet(cx, bce, pn->getOp());
+ return true;
+}
+
+static bool
+EmitSelfHostedResumeGenerator(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
+{
+ // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'close')
+ if (pn->pn_count != 4) {
+ bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
+ return false;
+ }
+
+ ParseNode *funNode = pn->pn_head; // The resumeGenerator node.
+
+ ParseNode *genNode = funNode->pn_next;
+ if (!EmitTree(cx, bce, genNode))
+ return false;
+
+ ParseNode *valNode = genNode->pn_next;
+ if (!EmitTree(cx, bce, valNode))
+ return false;
+
+ ParseNode *kindNode = valNode->pn_next;
+ MOZ_ASSERT(kindNode->isKind(PNK_STRING));
+ uint16_t operand = GeneratorObject::getResumeKind(cx, kindNode->pn_atom);
+ MOZ_ASSERT(!kindNode->pn_next);
+
+ if (EmitCall(cx, bce, JSOP_RESUME, operand) < 0)
+ return false;
+
+ return true;
+}
+
static bool
EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
@@ -5835,46 +5964,21 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false;
}
- bool emitArgs = true;
ParseNode *pn2 = pn->pn_head;
bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
switch (pn2->getKind()) {
case PNK_NAME:
- if (bce->emitterMode == BytecodeEmitter::SelfHosting &&
- pn2->name() == cx->names().callFunction &&
- !spread)
- {
- /*
- * Special-casing of callFunction to emit bytecode that directly
- * invokes the callee with the correct |this| object and arguments.
- * callFunction(fun, thisArg, arg0, arg1) thus becomes:
- * - emit lookup for fun
- * - emit lookup for thisArg
- * - emit lookups for arg0, arg1
- *
- * argc is set to the amount of actually emitted args and the
- * emitting of args below is disabled by setting emitArgs to false.
- */
- if (pn->pn_count < 3) {
- bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "callFunction", "1", "s");
- return false;
- }
- ParseNode *funNode = pn2->pn_next;
- if (!EmitTree(cx, bce, funNode))
- return false;
- ParseNode *thisArg = funNode->pn_next;
- if (!EmitTree(cx, bce, thisArg))
- return false;
- bool oldEmittingForInit = bce->emittingForInit;
- bce->emittingForInit = false;
- for (ParseNode *argpn = thisArg->pn_next; argpn; argpn = argpn->pn_next) {
- if (!EmitTree(cx, bce, argpn))
- return false;
- }
- bce->emittingForInit = oldEmittingForInit;
- argc -= 2;
- emitArgs = false;
- break;
+ if (bce->emitterMode == BytecodeEmitter::SelfHosting && !spread) {
+ // We shouldn't see foo(bar) = x in self-hosted code.
+ MOZ_ASSERT(!(pn->pn_xflags & PNX_SETCALL));
+
+ // Calls to "callFunction" or "resumeGenerator" in self-hosted code
+ // generate inline bytecode.
+ if (pn2->name() == cx->names().callFunction)
+ return EmitSelfHostedCallFunction(cx, bce, pn);
+ if (pn2->name() == cx->names().resumeGenerator)
+ return EmitSelfHostedResumeGenerator(cx, bce, pn);
+ // Fall through.
}
if (!EmitNameOp(cx, bce, pn2, callop))
return false;
@@ -5922,25 +6026,23 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false;
}
- if (emitArgs) {
- /*
- * Emit code for each argument in order, then emit the JSOP_*CALL or
- * JSOP_NEW bytecode with a two-byte immediate telling how many args
- * were pushed on the operand stack.
- */
- bool oldEmittingForInit = bce->emittingForInit;
- bce->emittingForInit = false;
- if (!spread) {
- for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
- if (!EmitTree(cx, bce, pn3))
- return false;
- }
- } else {
- if (!EmitArray(cx, bce, pn2->pn_next, argc))
+ /*
+ * Emit code for each argument in order, then emit the JSOP_*CALL or
+ * JSOP_NEW bytecode with a two-byte immediate telling how many args
+ * were pushed on the operand stack.
+ */
+ bool oldEmittingForInit = bce->emittingForInit;
+ bce->emittingForInit = false;
+ if (!spread) {
+ for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
+ if (!EmitTree(cx, bce, pn3))
return false;
}
- bce->emittingForInit = oldEmittingForInit;
+ } else {
+ if (!EmitArray(cx, bce, pn2->pn_next, argc))
+ return false;
}
+ bce->emittingForInit = oldEmittingForInit;
if (!spread) {
if (EmitCall(cx, bce, pn->getOp(), argc, pn) < 0)
@@ -6687,28 +6789,16 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
break;
case PNK_YIELD_STAR:
- ok = EmitYieldStar(cx, bce, pn->pn_kid);
+ ok = EmitYieldStar(cx, bce, pn->pn_left, pn->pn_right);
+ break;
+
+ case PNK_GENERATOR:
+ if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
+ return false;
break;
case PNK_YIELD:
- MOZ_ASSERT(bce->sc->isFunctionBox());
- if (bce->sc->asFunctionBox()->isStarGenerator()) {
- if (!EmitPrepareIteratorResult(cx, bce))
- return false;
- }
- if (pn->pn_kid) {
- if (!EmitTree(cx, bce, pn->pn_kid))
- return false;
- } else {
- if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
- return false;
- }
- if (bce->sc->asFunctionBox()->isStarGenerator()) {
- if (!EmitFinishIteratorResult(cx, bce, false))
- return false;
- }
- if (Emit1(cx, bce, JSOP_YIELD) < 0)
- return false;
+ ok = EmitYield(cx, bce, pn);
break;
case PNK_STATEMENTLIST:
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index a7c16bf246b3..a86dcff80a98 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -323,6 +323,17 @@ class FullParseHandler
return true;
}
+ ParseNode *newYieldExpression(uint32_t begin, ParseNode *value, ParseNode *gen,
+ JSOp op = JSOP_YIELD) {
+ TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
+ return new_(PNK_YIELD, op, pos, value, gen);
+ }
+
+ ParseNode *newYieldStarExpression(uint32_t begin, ParseNode *value, ParseNode *gen) {
+ TokenPos pos(begin, value->pn_pos.end);
+ return new_(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
+ }
+
// Statements
ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) {
@@ -352,6 +363,31 @@ class FullParseHandler
list->append(stmt);
}
+ bool prependInitialYield(ParseNode *stmtList, ParseNode *genName) {
+ MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
+
+ TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
+ ParseNode *makeGen = new_(PNK_GENERATOR, yieldPos);
+ if (!makeGen)
+ return false;
+
+ MOZ_ASSERT(genName->getOp() == JSOP_NAME);
+ genName->setOp(JSOP_SETNAME);
+ genName->markAsAssigned();
+ ParseNode *genInit = newBinary(PNK_ASSIGN, genName, makeGen);
+
+ ParseNode *initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
+ JSOP_INITIALYIELD);
+ if (!initialYield)
+ return false;
+
+ initialYield->pn_next = stmtList->pn_head;
+ stmtList->pn_head = initialYield;
+ stmtList->pn_count++;
+
+ return true;
+ }
+
ParseNode *newEmptyStatement(const TokenPos &pos) {
return new_(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr);
}
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index c3bc7c147eb8..dfefe5a4248a 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -124,6 +124,7 @@ class UpvarCookie
F(FINALLY) \
F(THROW) \
F(DEBUGGER) \
+ F(GENERATOR) \
F(YIELD) \
F(YIELD_STAR) \
F(GENEXP) \
@@ -422,6 +423,9 @@ enum ParseNodeKind
*
* PNK_LEXICALSCOPE name pn_objbox: block object in ObjectBox holder
* pn_expr: block body
+ * PNK_GENERATOR nullary
+ * PNK_YIELD, binary pn_left: expr or null; pn_right: generator object
+ * PNK_YIELD_STAR
* PNK_ARRAYCOMP list pn_count: 1
* pn_head: list of 1 element, which is block
* enclosing for loop(s) and optionally
@@ -773,8 +777,9 @@ class ParseNode
MOZ_ASSERT(isKind(PNK_GENEXP));
ParseNode *callee = this->pn_head;
ParseNode *body = callee->pn_body;
- MOZ_ASSERT(body->isKind(PNK_LEXICALSCOPE) || body->isKind(PNK_FOR));
- return body;
+ MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
+ MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) || body->last()->isKind(PNK_FOR));
+ return body->last();
}
#endif
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 0bdc72b83eb0..c77ed18c8a80 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1035,6 +1035,23 @@ Parser::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ
break;
}
+ if (pc->isGenerator()) {
+ MOZ_ASSERT(type == StatementListBody);
+ Node generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!pc->define(tokenStream, context->names().dotGenerator, generator, Definition::VAR))
+ return null();
+
+ generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!noteNameUse(context->names().dotGenerator, generator))
+ return null();
+ if (!handler.prependInitialYield(pn, generator))
+ return null();
+ }
+
/* Define the 'arguments' binding if necessary. */
if (!checkFunctionArguments())
return null();
@@ -5007,6 +5024,21 @@ Parser::returnStatement()
return pn;
}
+template
+typename ParseHandler::Node
+Parser::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
+ bool isYieldStar)
+{
+ Node generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!noteNameUse(context->names().dotGenerator, generator))
+ return null();
+ if (isYieldStar)
+ return handler.newYieldStarExpression(begin, expr, generator);
+ return handler.newYieldExpression(begin, expr, generator);
+}
+
template
typename ParseHandler::Node
Parser::yieldExpression()
@@ -5052,7 +5084,7 @@ Parser::yieldExpression()
if (!exprNode)
return null();
}
- return handler.newUnary(kind, JSOP_NOP, begin, exprNode);
+ return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
}
case NotGenerator:
@@ -5110,7 +5142,7 @@ Parser::yieldExpression()
return null();
}
- return handler.newUnary(PNK_YIELD, JSOP_NOP, begin, exprNode);
+ return newYieldExpression(begin, exprNode);
}
}
@@ -6189,9 +6221,17 @@ LegacyCompExprTransplanter::transplant(ParseNode *pn)
MOZ_ASSERT(!stmt || stmt != pc->topStmt);
#endif
if (isGenexp && !dn->isOp(JSOP_CALLEE)) {
- MOZ_ASSERT(!pc->decls().lookupFirst(atom));
+ MOZ_ASSERT_IF(atom != parser->context->names().dotGenerator,
+ !pc->decls().lookupFirst(atom));
- if (dn->pn_pos < root->pn_pos) {
+ if (atom == parser->context->names().dotGenerator) {
+ if (dn->dn_uses == pn) {
+ if (!BumpStaticLevel(parser->tokenStream, dn, pc))
+ return false;
+ if (!AdjustBlockId(parser->tokenStream, dn, adjust, pc))
+ return false;
+ }
+ } else if (dn->pn_pos < root->pn_pos) {
/*
* The variable originally appeared to be a use of a
* definition or placeholder outside the generator, but now
@@ -6304,7 +6344,7 @@ LegacyComprehensionHeadBlockScopeDepth(ParseContext *pc)
*/
template <>
ParseNode *
-Parser::legacyComprehensionTail(ParseNode *bodyStmt, unsigned blockid,
+Parser::legacyComprehensionTail(ParseNode *bodyExpr, unsigned blockid,
GeneratorKind comprehensionKind,
ParseContext *outerpc,
unsigned innerBlockScopeDepth)
@@ -6368,15 +6408,15 @@ Parser::legacyComprehensionTail(ParseNode *bodyStmt, unsigned
adjust = blockid - adjust;
}
- handler.setBeginPosition(pn, bodyStmt);
+ handler.setBeginPosition(pn, bodyExpr);
pnp = &pn->pn_expr;
- LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
+ LegacyCompExprTransplanter transplanter(bodyExpr, this, outerpc, comprehensionKind, adjust);
if (!transplanter.init())
return null();
- if (!transplanter.transplant(bodyStmt))
+ if (!transplanter.transplant(bodyExpr))
return null();
MOZ_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
@@ -6532,6 +6572,23 @@ Parser::legacyComprehensionTail(ParseNode *bodyStmt, unsigned
pnp = &pn2->pn_kid2;
}
+ ParseNode *bodyStmt;
+ if (isGenexp) {
+ ParseNode *yieldExpr = newYieldExpression(bodyExpr->pn_pos.begin, bodyExpr);
+ if (!yieldExpr)
+ return null();
+ yieldExpr->setInParens(true);
+
+ bodyStmt = handler.newExprStatement(yieldExpr, bodyExpr->pn_pos.end);
+ if (!bodyStmt)
+ return null();
+ } else {
+ bodyStmt = handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH,
+ bodyExpr->pn_pos.begin, bodyExpr);
+ if (!bodyStmt)
+ return null();
+ }
+
*pnp = bodyStmt;
pc->topStmt->innerBlockScopeDepth += innerBlockScopeDepth;
@@ -6568,12 +6625,7 @@ Parser::legacyArrayComprehension(ParseNode *array)
array->pn_tail = &array->pn_head;
*array->pn_tail = nullptr;
- ParseNode *arrayPush = handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH,
- bodyExpr->pn_pos.begin, bodyExpr);
- if (!arrayPush)
- return null();
-
- ParseNode *comp = legacyComprehensionTail(arrayPush, array->pn_blockid, NotGenerator,
+ ParseNode *comp = legacyComprehensionTail(bodyExpr, array->pn_blockid, NotGenerator,
nullptr, LegacyComprehensionHeadBlockScopeDepth(pc));
if (!comp)
return null();
@@ -6596,10 +6648,10 @@ Parser::legacyArrayComprehension(Node array)
template
typename ParseHandler::Node
Parser::generatorComprehensionLambda(GeneratorKind comprehensionKind,
- unsigned begin, Node innerStmt)
+ unsigned begin, Node innerExpr)
{
MOZ_ASSERT(comprehensionKind == LegacyGenerator || comprehensionKind == StarGenerator);
- MOZ_ASSERT(!!innerStmt == (comprehensionKind == LegacyGenerator));
+ MOZ_ASSERT(!!innerExpr == (comprehensionKind == LegacyGenerator));
Node genfn = handler.newFunctionDefinition();
if (!genfn)
@@ -6650,29 +6702,47 @@ Parser::generatorComprehensionLambda(GeneratorKind comprehensionKi
genFunbox->inGenexpLambda = true;
handler.setBlockId(genfn, genpc.bodyid);
- Node body;
+ Node generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!pc->define(tokenStream, context->names().dotGenerator, generator, Definition::VAR))
+ return null();
+ Node body = handler.newStatementList(pc->blockid(), TokenPos(begin, pos().end));
+ if (!body)
+ return null();
+
+ Node comp;
if (comprehensionKind == StarGenerator) {
- body = comprehension(StarGenerator);
- if (!body)
+ comp = comprehension(StarGenerator);
+ if (!comp)
return null();
} else {
MOZ_ASSERT(comprehensionKind == LegacyGenerator);
- body = legacyComprehensionTail(innerStmt, outerpc->blockid(), LegacyGenerator,
+ comp = legacyComprehensionTail(innerExpr, outerpc->blockid(), LegacyGenerator,
outerpc, LegacyComprehensionHeadBlockScopeDepth(outerpc));
- if (!body)
+ if (!comp)
return null();
}
if (comprehensionKind == StarGenerator)
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
- handler.setBeginPosition(body, begin);
+ handler.setBeginPosition(comp, begin);
+ handler.setEndPosition(comp, pos().end);
+ handler.addStatementToList(body, comp, pc);
handler.setEndPosition(body, pos().end);
-
handler.setBeginPosition(genfn, begin);
handler.setEndPosition(genfn, pos().end);
+ generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!noteNameUse(context->names().dotGenerator, generator))
+ return null();
+ if (!handler.prependInitialYield(body, generator))
+ return null();
+
// Note that if we ever start syntax-parsing generators, we will also
// need to propagate the closed-over variable set to the inner
// lazyscript, as in finishFunctionDefinition.
@@ -6709,19 +6779,8 @@ Parser::legacyGeneratorExpr(ParseNode *expr)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
- /* Create a |yield| node for |kid|. */
- ParseNode *yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, expr->pn_pos.begin, expr);
- if (!yieldExpr)
- return null();
- yieldExpr->setInParens(true);
-
- // A statement to wrap the yield expression.
- ParseNode *yieldStmt = handler.newExprStatement(yieldExpr, expr->pn_pos.end);
- if (!yieldStmt)
- return null();
-
/* Make a new node for the desugared generator function. */
- ParseNode *genfn = generatorComprehensionLambda(LegacyGenerator, expr->pn_pos.begin, yieldStmt);
+ ParseNode *genfn = generatorComprehensionLambda(LegacyGenerator, expr->pn_pos.begin, expr);
if (!genfn)
return null();
@@ -6871,7 +6930,7 @@ Parser::comprehensionTail(GeneratorKind comprehensionKind)
return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
MOZ_ASSERT(comprehensionKind == StarGenerator);
- Node yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, begin, bodyExpr);
+ Node yieldExpr = newYieldExpression(begin, bodyExpr);
if (!yieldExpr)
return null();
handler.setInParens(yieldExpr);
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index d4e6ad9c1afb..b1826c7f7aa6 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -464,6 +464,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
bool addExprAndGetNextTemplStrToken(Node nodeList, TokenKind &tt);
inline Node newName(PropertyName *name);
+ inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
inline bool abortIfSyntaxParser();
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index 7073a71bc07a..7154ff56d282 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -135,11 +135,14 @@ class SyntaxParseHandler
bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
bool addPropertyDefinition(Node literal, Node name, Node expr, bool isShorthand = false) { return true; }
bool addMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
+ Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+ Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
// Statements
Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; }
void addStatementToList(Node list, Node stmt, ParseContext *pc) {}
+ bool prependInitialYield(Node stmtList, Node gen) { return true; }
Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; }
Node newExprStatement(Node expr, uint32_t end) {
diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h
index cb5cfdc0b78f..972674c0689c 100644
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -25,7 +25,7 @@
* - writes to object properties
* - writes to array slots
* - writes to fields like JSObject::shape_ that we trace through
- * - writes to fields in private data, like JSGenerator::obj
+ * - writes to fields in private data
* - writes to non-markable fields like JSObject::private that point to
* markable data
* The last category is the trickiest. Even though the private pointers does not
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-generators-01.js b/js/src/jit-test/tests/debug/Frame-onPop-generators-01.js
index 3b8b8810b8b4..35b4d29621ca 100644
--- a/js/src/jit-test/tests/debug/Frame-onPop-generators-01.js
+++ b/js/src/jit-test/tests/debug/Frame-onPop-generators-01.js
@@ -1,5 +1,6 @@
+// |jit-test| error: StopIteration
// Returning {throw:} from an onPop handler when yielding works and
-// does not close the generator-iterator.
+// does closes the generator-iterator.
load(libdir + "asserts.js");
@@ -17,4 +18,4 @@ var rv = gw.evalInGlobal("it.next();");
assertEq(rv.throw, "fit");
dbg.enabled = false;
-assertEq(g.it.next(), 1);
+g.it.next();
diff --git a/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js b/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
index c8edd53744d3..b26f0ef7394e 100644
--- a/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
+++ b/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
@@ -1,5 +1,5 @@
// Returning {throw:} from an onPop handler when yielding works and
-// does not close the generator-iterator.
+// closes the generator-iterator.
load(libdir + "iteration.js");
@@ -17,4 +17,4 @@ var rv = gw.evalInGlobal("it.next();");
assertEq(rv.throw, "fit");
dbg.enabled = false;
-assertIteratorNext(g.it, 1);
+assertIteratorDone(g.it);
diff --git a/js/src/jit-test/tests/debug/resumption-04.js b/js/src/jit-test/tests/debug/resumption-04.js
index d564a7a75ace..1309871eab81 100644
--- a/js/src/jit-test/tests/debug/resumption-04.js
+++ b/js/src/jit-test/tests/debug/resumption-04.js
@@ -1,3 +1,4 @@
+// |jit-test| error: already executing generator
// Forced return from a generator frame.
var g = newGlobal();
@@ -10,5 +11,9 @@ function gen() {
debugger; // Force return here. The value is ignored.
yield '2';
}
-var x = [v for (v in gen())];
-assertEq(x.join(","), "1");
+
+var iter = gen();
+assertEq(iter.next(), "1");
+assertEq(iter.next(), "!");
+iter.next();
+assertEq(0, 1);
diff --git a/js/src/jit-test/tests/debug/resumption-06.js b/js/src/jit-test/tests/debug/resumption-06.js
index 43010c28d832..4b58e3e464b9 100644
--- a/js/src/jit-test/tests/debug/resumption-06.js
+++ b/js/src/jit-test/tests/debug/resumption-06.js
@@ -1,3 +1,4 @@
+// |jit-test| error: already executing generator
// Forced return from a star generator frame.
load(libdir + 'asserts.js')
@@ -16,4 +17,5 @@ function* gen() {
var iter = gen();
assertIteratorNext(iter, '1');
assertEq(iter.next(), '!');
-assertIteratorDone(iter);
+iter.next();
+assertEq(0, 1);
diff --git a/js/src/jit-test/tests/generators/throw-closes.js b/js/src/jit-test/tests/generators/throw-closes.js
new file mode 100644
index 000000000000..ffadbb4f1ea1
--- /dev/null
+++ b/js/src/jit-test/tests/generators/throw-closes.js
@@ -0,0 +1,49 @@
+// When a generator function throws, the generator is closed.
+
+load(libdir + "asserts.js");
+load(libdir + "iteration.js");
+
+// Star generator, next() throws.
+function *g() {
+ yield 1;
+ yield 2;
+ throw 3;
+ yield 4;
+}
+var i = g();
+assertIteratorNext(i, 1);
+assertIteratorNext(i, 2);
+assertThrowsValue(() => i.next(), 3);
+assertIteratorDone(i);
+assertIteratorDone(i);
+
+// Star generator, throw() throws.
+function *h() {
+ yield 1;
+ yield 2;
+}
+var i = h();
+assertIteratorNext(i, 1);
+assertThrowsValue(() => i.throw(4), 4);
+assertIteratorDone(i);
+
+// Legacy generator, throw() throws.
+function l1() {
+ yield 1;
+ yield 2;
+}
+var i = l1();
+assertEq(i.next(), 1);
+assertThrowsValue(() => i.throw(5), 5);
+assertThrowsInstanceOf(() => i.next(), StopIteration);
+
+// Legacy generator, next() throws.
+function l2() {
+ yield 1;
+ throw 6;
+ yield 2;
+}
+var i = l2();
+assertEq(i.next(), 1);
+assertThrowsValue(() => i.next(), 6);
+assertThrowsInstanceOf(() => i.next(), StopIteration);
diff --git a/js/src/jit-test/tests/generators/wrappers.js b/js/src/jit-test/tests/generators/wrappers.js
new file mode 100644
index 000000000000..1e7c03a7d0b9
--- /dev/null
+++ b/js/src/jit-test/tests/generators/wrappers.js
@@ -0,0 +1,34 @@
+// Generator methods work transparently on CrossCompartmentWrappers.
+
+load(libdir + "asserts.js");
+load(libdir + "iteration.js");
+
+function gen() { yield 1; yield 2; }
+var it = gen();
+
+var g = newGlobal();
+g.eval("function gen2() { yield 3; yield 4; }; var it2 = gen2();");
+
+// LegacyGenerator.next
+assertEq(it.next.call(g.it2), 3);
+
+// LegacyGenerator.throw
+assertThrowsValue(() => it.throw.call(g.it2, 7), 7);
+
+function *gen3() { yield 1; yield 2; }
+it = gen3();
+g.eval("function *gen4() { yield 5; yield 6; }; var it4 = gen4();");
+
+// StarGenerator.next
+assertIteratorResult(it.next.call(g.it4), 5, false)
+
+// StarGenerator.throw
+assertThrowsValue(() => it.throw.call(g.it4, 8), 8);
+
+// Other objects should throw.
+try {
+ it.next.call([]);
+ assertEq(0, 1);
+} catch (e) {
+ assertEq(e.toString().contains("called on incompatible Array"), true);
+}
diff --git a/js/src/jit-test/tests/saved-stacks/generators.js b/js/src/jit-test/tests/saved-stacks/generators.js
index 69cd1e4adf38..7d75c5685ccc 100644
--- a/js/src/jit-test/tests/saved-stacks/generators.js
+++ b/js/src/jit-test/tests/saved-stacks/generators.js
@@ -10,6 +10,7 @@ const { value: frame } = (function iife1() {
assertEq(frame.functionDisplayName, "iife2");
assertEq(frame.parent.functionDisplayName, "generator");
-assertEq(frame.parent.parent.functionDisplayName, "iife1");
-assertEq(frame.parent.parent.parent.functionDisplayName, null);
-assertEq(frame.parent.parent.parent.parent, null);
+assertEq(frame.parent.parent.functionDisplayName, "next");
+assertEq(frame.parent.parent.parent.functionDisplayName, "iife1");
+assertEq(frame.parent.parent.parent.parent.functionDisplayName, null);
+assertEq(frame.parent.parent.parent.parent.parent, null);
diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp
index 13bc359a858d..00d35450c9a1 100644
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -49,7 +49,9 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
MOZ_ASSERT(IsBaselineEnabled(cx));
*bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo);
+ bool poppedLastSPSFrame = false;
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
+ /* excInfo = */ nullptr, &poppedLastSPSFrame);
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
@@ -68,7 +70,8 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
// pseudostack frame would not have been pushed in the first
// place, so don't pop anything in that case.
bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
- (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
+ (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
+ !poppedLastSPSFrame;
JSScript *script = iter.script();
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
@@ -105,7 +108,9 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
MOZ_ASSERT(IsBaselineEnabled(cx));
*bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo);
+ bool poppedLastSPSFrame = false;
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo,
+ /* excInfo = */ nullptr, &poppedLastSPSFrame);
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
@@ -124,7 +129,8 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
// pseudostack frame would not have been pushed in the first
// place, so don't pop anything in that case.
bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
- (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
+ (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
+ !poppedLastSPSFrame;
JSScript *script = iter.script();
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
@@ -180,7 +186,9 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
JitFrameIterator iter(jitActivations);
BaselineBailoutInfo *bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo);
+ bool poppedLastSPSFrame = false;
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true,
+ &bailoutInfo, &excInfo, &poppedLastSPSFrame);
if (retval == BAILOUT_RETURN_OK) {
MOZ_ASSERT(bailoutInfo);
diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp
index 24fdad6a012d..c0ee98dbc2c6 100644
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -515,9 +515,12 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
HandleFunction fun, HandleScript script, IonScript *ionScript,
SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
AutoValueVector &startFrameFormals, MutableHandleFunction nextCallee,
- jsbytecode **callPC, const ExceptionBailoutInfo *excInfo)
+ jsbytecode **callPC, const ExceptionBailoutInfo *excInfo,
+ bool *poppedLastSPSFrameOut)
{
MOZ_ASSERT(script->hasBaselineScript());
+ MOZ_ASSERT(poppedLastSPSFrameOut);
+ MOZ_ASSERT(!*poppedLastSPSFrameOut);
// Are we catching an exception?
bool catchingException = excInfo && excInfo->catchingException();
@@ -1035,6 +1038,11 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
JitSpew(JitSpew_BaselineBailouts,
" Popping SPS entry for outermost frame");
cx->runtime()->spsProfiler.exit(script, fun);
+
+ // Notify caller that the last SPS frame was popped, so not
+ // to do it again.
+ if (poppedLastSPSFrameOut)
+ *poppedLastSPSFrameOut = true;
}
}
} else {
@@ -1291,7 +1299,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
uint32_t
jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo,
- const ExceptionBailoutInfo *excInfo)
+ const ExceptionBailoutInfo *excInfo, bool *poppedLastSPSFrameOut)
{
// The Baseline frames we will reconstruct on the heap are not rooted, so GC
// must be suppressed here.
@@ -1300,6 +1308,9 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
MOZ_ASSERT(bailoutInfo != nullptr);
MOZ_ASSERT(*bailoutInfo == nullptr);
+ MOZ_ASSERT(poppedLastSPSFrameOut);
+ MOZ_ASSERT(!*poppedLastSPSFrameOut);
+
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
TraceLogStartEvent(logger, TraceLogger::Baseline);
@@ -1429,7 +1440,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
RootedFunction nextCallee(cx, nullptr);
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
snapIter, invalidate, builder, startFrameFormals,
- &nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
+ &nextCallee, &callPC, passExcInfo ? excInfo : nullptr,
+ poppedLastSPSFrameOut))
{
return BAILOUT_RETURN_FATAL_ERROR;
}
diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp
index a34ca4f83721..3a2f32b13ec0 100644
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -323,16 +323,13 @@ jit::CanEnterBaselineMethod(JSContext *cx, RunState &state)
if (!state.maybeCreateThisForConstructor(cx))
return Method_Skipped;
- } else if (state.isExecute()) {
+ } else {
+ MOZ_ASSERT(state.isExecute());
ExecuteType type = state.asExecute()->type();
if (type == EXECUTE_DEBUG || type == EXECUTE_DEBUG_GLOBAL) {
JitSpew(JitSpew_BaselineAbort, "debugger frame");
return Method_CantCompile;
}
- } else {
- MOZ_ASSERT(state.isGenerator());
- JitSpew(JitSpew_BaselineAbort, "generator frame");
- return Method_CantCompile;
}
RootedScript script(cx, state.script());
diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h
index 6800fd891166..89243877a66b 100644
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -439,7 +439,8 @@ struct BaselineBailoutInfo
uint32_t
BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo,
- const ExceptionBailoutInfo *exceptionInfo = nullptr);
+ const ExceptionBailoutInfo *exceptionInfo,
+ bool *poppedLastSPSFrame);
// Mark baseline scripts on the stack as active, so that they are not discarded
// during GC.
diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
index 13b005764d21..acac206820f5 100644
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2401,10 +2401,6 @@ jit::CanEnter(JSContext *cx, RunState &state)
if (!state.maybeCreateThisForConstructor(cx))
return Method_Skipped;
- } else if (state.isGenerator()) {
- JitSpew(JitSpew_IonAbort, "generator frame");
- ForbidCompilation(cx, script);
- return Method_CantCompile;
}
// If --ion-eager is used, compile with Baseline first, so that we
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index ff7fe5d6b5c7..39b6e4014277 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2781,7 +2781,8 @@ JS_AlreadyHasOwnUCProperty(JSContext *cx, HandleObject obj, const char16_t *name
return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
}
-/* Wrapper functions to create wrappers with no corresponding JSJitInfo from API
+/*
+ * Wrapper functions to create wrappers with no corresponding JSJitInfo from API
* function arguments.
*/
static JSPropertyOpWrapper
@@ -2825,8 +2826,6 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val
MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
JSFunction::Flags zeroFlags = JSAPIToJSFunctionFlags(0);
- // We can't just use JS_NewFunctionById here because it assumes a
- // string id.
RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
attrs &= ~JSPROP_NATIVE_ACCESSORS;
if (getter) {
@@ -2863,12 +2862,12 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id, value,
- (attrs & JSPROP_GETTER)
- ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
- : nullptr,
- (attrs & JSPROP_SETTER)
- ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
- : nullptr);
+ (attrs & JSPROP_GETTER)
+ ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
+ : nullptr,
+ (attrs & JSPROP_SETTER)
+ ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
+ : nullptr);
return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
}
@@ -3012,30 +3011,22 @@ DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue va
return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags);
}
-
static bool
-DefineSelfHostedProperty(JSContext *cx,
- HandleObject obj,
- const char *name,
- const char *getterName,
- const char *setterName,
- unsigned attrs,
- unsigned flags)
+DefineSelfHostedProperty(JSContext *cx, HandleObject obj, HandleId id,
+ const char *getterName, const char *setterName,
+ unsigned attrs, unsigned flags)
{
- RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name)));
- if (!nameAtom)
- return false;
-
RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName)));
if (!getterNameAtom)
return false;
- RootedValue getterValue(cx);
- if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom,
- 0, &getterValue))
- {
+ RootedAtom name(cx, IdToFunctionName(cx, id));
+ if (!name)
+ return false;
+
+ RootedValue getterValue(cx);
+ if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, name, 0, &getterValue))
return false;
- }
MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is());
RootedFunction getterFunc(cx, &getterValue.toObject().as());
JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get());
@@ -3047,19 +3038,16 @@ DefineSelfHostedProperty(JSContext *cx,
return false;
RootedValue setterValue(cx);
- if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom,
- 0, &setterValue))
- {
+ if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, name, 0, &setterValue))
return false;
- }
MOZ_ASSERT(setterValue.isObject() && setterValue.toObject().is());
setterFunc = &getterValue.toObject().as();
}
JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get());
- return DefineProperty(cx, obj, name, JS::UndefinedHandleValue,
- GetterWrapper(getterOp), SetterWrapper(setterOp),
- attrs, flags);
+ return DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
+ GetterWrapper(getterOp), SetterWrapper(setterOp),
+ attrs, flags);
}
JS_PUBLIC_API(bool)
@@ -3256,37 +3244,81 @@ JS_DefineConstIntegers(JSContext *cx, HandleObject obj, const JSConstIntegerSpec
return DefineConstScalar(cx, obj, cis);
}
+static JS::SymbolCode
+PropertySpecNameToSymbolCode(const char *name)
+{
+ MOZ_ASSERT(JS::PropertySpecNameIsSymbol(name));
+ uintptr_t u = reinterpret_cast(name);
+ return JS::SymbolCode(u - 1);
+}
+
+static bool
+PropertySpecNameToId(JSContext *cx, const char *name, MutableHandleId id,
+ js::InternBehavior ib = js::DoNotInternAtom)
+{
+ if (JS::PropertySpecNameIsSymbol(name)) {
+ JS::SymbolCode which = PropertySpecNameToSymbolCode(name);
+ id.set(SYMBOL_TO_JSID(cx->wellKnownSymbols().get(which)));
+ } else {
+ JSAtom *atom = Atomize(cx, name, strlen(name), ib);
+ if (!atom)
+ return false;
+ id.set(AtomToId(atom));
+ }
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS::PropertySpecNameToPermanentId(JSContext *cx, const char *name, jsid *idp)
+{
+ // We are calling fromMarkedLocation(idp) even though idp points to a
+ // location that will never be marked. This is OK because the whole point
+ // of this API is to populate *idp with a jsid that does not need to be
+ // marked.
+ return PropertySpecNameToId(cx, name, MutableHandleId::fromMarkedLocation(idp),
+ js::InternAtom);
+}
+
JS_PUBLIC_API(bool)
JS_DefineProperties(JSContext *cx, HandleObject obj, const JSPropertySpec *ps)
{
- bool ok;
- for (ok = true; ps->name; ps++) {
+ RootedId id(cx);
+
+ for (; ps->name; ps++) {
+ if (!PropertySpecNameToId(cx, ps->name, &id))
+ return false;
+
if (ps->flags & JSPROP_NATIVE_ACCESSORS) {
// If you declare native accessors, then you should have a native
// getter.
MOZ_ASSERT(ps->getter.propertyOp.op);
+
// If you do not have a self-hosted getter, you should not have a
// self-hosted setter. This is the closest approximation to that
// assertion we can have with our setup.
MOZ_ASSERT_IF(ps->setter.propertyOp.info, ps->setter.propertyOp.op);
- ok = DefineProperty(cx, obj, ps->name, JS::UndefinedHandleValue,
- ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0);
+ if (!DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
+ ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0))
+ {
+ return false;
+ }
} else {
// If you have self-hosted getter/setter, you can't have a
// native one.
MOZ_ASSERT(!ps->getter.propertyOp.op && !ps->setter.propertyOp.op);
MOZ_ASSERT(ps->flags & JSPROP_GETTER);
- ok = DefineSelfHostedProperty(cx, obj, ps->name,
+ if (!DefineSelfHostedProperty(cx, obj, id,
ps->getter.selfHosted.funname,
ps->setter.selfHosted.funname,
- ps->flags, 0);
+ ps->flags, 0))
+ {
+ return false;
+ }
}
- if (!ok)
- break;
}
- return ok;
+ return true;
}
JS_PUBLIC_API(bool)
@@ -3620,137 +3652,6 @@ JS_Enumerate(JSContext *cx, HandleObject obj)
return ida;
}
-/*
- * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
- * prop_iterator_class somehow...
- * + preserve the obj->enumerate API while optimizing the native object case
- * + native case here uses a JSShape *, but that iterates in reverse!
- * + so we make non-native match, by reverse-iterating after JS_Enumerating
- */
-static const uint32_t JSSLOT_ITER_INDEX = 0;
-
-static void
-prop_iter_finalize(FreeOp *fop, JSObject *obj)
-{
- void *pdata = obj->as().getPrivate();
- if (!pdata)
- return;
-
- if (obj->as().getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
- /* Non-native case: destroy the ida enumerated when obj was created. */
- JSIdArray *ida = (JSIdArray *) pdata;
- fop->free_(ida);
- }
-}
-
-static void
-prop_iter_trace(JSTracer *trc, JSObject *obj)
-{
- void *pdata = obj->as().getPrivate();
- if (!pdata)
- return;
-
- if (obj->as().getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
- /*
- * Native case: just mark the next property to visit. We don't need a
- * barrier here because the pointer is updated via setPrivate, which
- * always takes a barrier.
- */
- Shape *tmp = static_cast(pdata);
- MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
- obj->as().setPrivateUnbarriered(tmp);
- } else {
- /* Non-native case: mark each id in the JSIdArray private. */
- JSIdArray *ida = (JSIdArray *) pdata;
- MarkIdRange(trc, ida->length, ida->vector, "prop iter");
- }
-}
-
-static const Class prop_iter_class = {
- "PropertyIterator",
- JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1),
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- prop_iter_finalize,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- prop_iter_trace
-};
-
-JS_PUBLIC_API(JSObject *)
-JS_NewPropertyIterator(JSContext *cx, HandleObject obj)
-{
- AssertHeapIsIdle(cx);
- CHECK_REQUEST(cx);
- assertSameCompartment(cx, obj);
-
- RootedNativeObject iterobj(cx, NewNativeObjectWithClassProto(cx, &prop_iter_class,
- nullptr, obj));
- if (!iterobj)
- return nullptr;
-
- int index;
- if (obj->isNative()) {
- /* Native case: start with the last property in obj. */
- iterobj->setPrivateGCThing(obj->lastProperty());
- index = -1;
- } else {
- /* Non-native case: enumerate a JSIdArray and keep it via private. */
- JSIdArray *ida = JS_Enumerate(cx, obj);
- if (!ida)
- return nullptr;
- iterobj->setPrivate((void *)ida);
- index = ida->length;
- }
-
- /* iterobj cannot escape to other threads here. */
- iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
- return iterobj;
-}
-
-JS_PUBLIC_API(bool)
-JS_NextProperty(JSContext *cx, HandleObject iterobj, MutableHandleId idp)
-{
- AssertHeapIsIdle(cx);
- CHECK_REQUEST(cx);
- assertSameCompartment(cx, iterobj);
- int32_t i = iterobj->as().getSlot(JSSLOT_ITER_INDEX).toInt32();
- if (i < 0) {
- /* Native case: private data is a property tree node pointer. */
- MOZ_ASSERT(iterobj->getParent()->isNative());
- Shape *shape = static_cast(iterobj->as().getPrivate());
-
- while (shape->previous() && !shape->enumerable())
- shape = shape->previous();
-
- if (!shape->previous()) {
- MOZ_ASSERT(shape->isEmptyShape());
- idp.set(JSID_VOID);
- } else {
- iterobj->as().setPrivateGCThing(const_cast(shape->previous().get()));
- idp.set(shape->propid());
- }
- } else {
- /* Non-native case: use the ida enumerated when iterobj was created. */
- JSIdArray *ida = (JSIdArray *) iterobj->as().getPrivate();
- MOZ_ASSERT(i <= ida->length);
- STATIC_ASSUME(i <= ida->length);
- if (i == 0) {
- idp.set(JSID_VOID);
- } else {
- idp.set(ida->vector[--i]);
- iterobj->as().setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
- }
- }
- return true;
-}
-
JS_PUBLIC_API(jsval)
JS_GetReservedSlot(JSObject *obj, uint32_t index)
{
@@ -3899,12 +3800,14 @@ JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flag
JS_PUBLIC_API(JSFunction *)
JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs)
{
- MOZ_ASSERT(JSID_IS_STRING(id));
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
- RootedAtom name(cx, JSID_TO_ATOM(id));
+ RootedAtom name(cx, IdToFunctionName(cx, id));
+ if (!name)
+ return nullptr;
+
RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
if (!shName)
return nullptr;
@@ -4068,21 +3971,11 @@ JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
+ RootedId id(cx);
for (; fs->name; fs++) {
- RootedAtom atom(cx);
- // If the name starts with "@@", it must be a well-known symbol.
- if (fs->name[0] != '@' || fs->name[1] != '@')
- atom = Atomize(cx, fs->name, strlen(fs->name));
- else if (strcmp(fs->name, "@@iterator") == 0)
- // FIXME: This atom should be a symbol: bug 918828.
- atom = cx->names().std_iterator;
- else
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_SYMBOL, fs->name);
- if (!atom)
+ if (!PropertySpecNameToId(cx, fs->name, &id))
return false;
- Rooted id(cx, AtomToId(atom));
-
/*
* Define a generic arity N+1 static method for the arity N prototype
* method if flags contains JSFUN_GENERIC_NATIVE.
@@ -4124,8 +4017,11 @@ JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
if (!shName)
return false;
+ RootedAtom name(cx, IdToFunctionName(cx, id));
+ if (!name)
+ return false;
RootedValue funVal(cx);
- if (!cx->global()->getSelfHostedFunction(cx, shName, atom, fs->nargs, &funVal))
+ if (!cx->global()->getSelfHostedFunction(cx, shName, name, fs->nargs, &funVal))
return false;
if (!JSObject::defineGeneric(cx, obj, id, funVal, nullptr, nullptr, flags))
return false;
@@ -5628,6 +5524,33 @@ JS::GetWellKnownSymbol(JSContext *cx, JS::SymbolCode which)
return cx->runtime()->wellKnownSymbols->get(uint32_t(which));
}
+static bool
+PropertySpecNameIsDigits(const char *s) {
+ if (JS::PropertySpecNameIsSymbol(s))
+ return false;
+ if (!*s)
+ return false;
+ for (; *s; s++) {
+ if (*s < '0' || *s > '9')
+ return false;
+ }
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS::PropertySpecNameEqualsId(const char *name, HandleId id)
+{
+ if (JS::PropertySpecNameIsSymbol(name)) {
+ if (!JSID_IS_SYMBOL(id))
+ return false;
+ Symbol *sym = JSID_TO_SYMBOL(id);
+ return sym->isWellKnownSymbol() && sym->code() == PropertySpecNameToSymbolCode(name);
+ }
+
+ MOZ_ASSERT(!PropertySpecNameIsDigits(name));
+ return JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_ATOM(id), name);
+}
+
JS_PUBLIC_API(bool)
JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
HandleValue space, JSONWriteCallback callback, void *data)
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 41b65c871fe0..50676f8a6040 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2475,15 +2475,27 @@ struct JSFunctionSpec {
* JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of
* JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. Finally
* JS_FNSPEC has slots for all the fields.
+ *
+ * The _SYM variants allow defining a function with a symbol key rather than a
+ * string key. For example, use JS_SYM_FN(iterator, ...) to define an
+ * @@iterator method.
*/
#define JS_FS(name,call,nargs,flags) \
JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
#define JS_FN(name,call,nargs,flags) \
JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
+#define JS_SYM_FN(name,call,nargs,flags) \
+ JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
#define JS_FNINFO(name,call,info,nargs,flags) \
JS_FNSPEC(name, call, info, nargs, flags, nullptr)
#define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \
JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
+#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
+ JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
+#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
+ JS_FNSPEC(reinterpret_cast( \
+ uint32_t(::JS::SymbolCode::symbol) + 1), \
+ call, info, nargs, flags, selfHostedName)
#define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \
{name, {call, info}, nargs, flags, selfHostedName}
@@ -3305,22 +3317,6 @@ JS_ReleaseMappedArrayBufferContents(void *contents, size_t length);
extern JS_PUBLIC_API(JSIdArray *)
JS_Enumerate(JSContext *cx, JS::HandleObject obj);
-/*
- * Create an object to iterate over enumerable properties of obj, in arbitrary
- * property definition order. NB: This differs from longstanding for..in loop
- * order, which uses order of property definition in obj.
- */
-extern JS_PUBLIC_API(JSObject *)
-JS_NewPropertyIterator(JSContext *cx, JS::Handle obj);
-
-/*
- * Return true on success with *idp containing the id of the next enumerable
- * property to visit using iterobj, or JSID_IS_VOID if there is no such property
- * left to visit. Return false on error.
- */
-extern JS_PUBLIC_API(bool)
-JS_NextProperty(JSContext *cx, JS::HandleObject iterobj, JS::MutableHandleId idp);
-
extern JS_PUBLIC_API(jsval)
JS_GetReservedSlot(JSObject *obj, uint32_t index);
@@ -4510,6 +4506,31 @@ GetSymbolCode(Handle symbol);
JS_PUBLIC_API(Symbol *)
GetWellKnownSymbol(JSContext *cx, SymbolCode which);
+/*
+ * Return true if the given JSPropertySpec::name or JSFunctionSpec::name value
+ * is actually a symbol code and not a string. See JS_SYM_FN.
+ */
+inline bool
+PropertySpecNameIsSymbol(const char *name)
+{
+ uintptr_t u = reinterpret_cast(name);
+ return u != 0 && u - 1 < WellKnownSymbolLimit;
+}
+
+JS_PUBLIC_API(bool)
+PropertySpecNameEqualsId(const char *name, HandleId id);
+
+/*
+ * Create a jsid that does not need to be marked for GC.
+ *
+ * 'name' is a JSPropertySpec::name or JSFunctionSpec::name value. The
+ * resulting jsid, on success, is either an interned string or a well-known
+ * symbol; either way it is immune to GC so there is no need to visit *idp
+ * during GC marking.
+ */
+JS_PUBLIC_API(bool)
+PropertySpecNameToPermanentId(JSContext *cx, const char *name, jsid *idp);
+
} /* namespace JS */
/************************************************************************/
diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp
index a744bc3126ff..62a0c66bb7ce 100644
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -58,7 +58,6 @@ const char js_break_str[] = "break";
const char js_case_str[] = "case";
const char js_catch_str[] = "catch";
const char js_class_str[] = "class";
-const char js_close_str[] = "close";
const char js_const_str[] = "const";
const char js_continue_str[] = "continue";
const char js_debugger_str[] = "debugger";
diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp
index 117eee762bef..a945b84dd022 100644
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1109,11 +1109,10 @@ JSContext::JSContext(JSRuntime *rt)
data(nullptr),
data2(nullptr),
outstandingRequests(0),
- jitIsBroken(false),
+ jitIsBroken(false)
#ifdef MOZ_TRACE_JSCALLS
- functionCallback(nullptr),
+ , functionCallback(nullptr)
#endif
- innermostGenerator_(nullptr)
{
MOZ_ASSERT(static_cast(this) ==
ContextFriendFields::get(this));
@@ -1146,23 +1145,6 @@ JSContext::isThrowingOutOfMemory()
return throwing && unwrappedException_ == StringValue(names().outOfMemory);
}
-void
-JSContext::enterGenerator(JSGenerator *gen)
-{
- MOZ_ASSERT(!gen->prevGenerator);
- gen->prevGenerator = innermostGenerator_;
- innermostGenerator_ = gen;
-}
-
-void
-JSContext::leaveGenerator(JSGenerator *gen)
-{
- MOZ_ASSERT(innermostGenerator_ == gen);
- innermostGenerator_ = innermostGenerator_->prevGenerator;
- gen->prevGenerator = nullptr;
-}
-
-
bool
JSContext::saveFrameChain()
{
diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
index d044b1dca164..91e1dd45f4b8 100644
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -284,6 +284,7 @@ struct ThreadSafeContext : ContextFriendFields,
JSAtomState &names() { return *runtime_->commonNames; }
StaticStrings &staticStrings() { return *runtime_->staticStrings; }
AtomSet &permanentAtoms() { return *runtime_->permanentAtoms; }
+ WellKnownSymbols &wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
const JS::AsmJSCacheOps &asmJSCacheOps() { return runtime_->asmJSCacheOps; }
PropertyName *emptyString() { return runtime_->emptyString; }
FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
@@ -551,14 +552,7 @@ struct JSContext : public js::ExclusiveContext,
runtime_->gc.gcIfNeeded(this);
}
- private:
- /* Innermost-executing generator or null if no generator are executing. */
- JSGenerator *innermostGenerator_;
public:
- JSGenerator *innermostGenerator() const { return innermostGenerator_; }
- void enterGenerator(JSGenerator *gen);
- void leaveGenerator(JSGenerator *gen);
-
bool isExceptionPending() {
return throwing;
}
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index 086cf1309ec7..70a757d657c6 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -971,7 +971,7 @@ CopyFlatStringChars(char16_t *dest, JSFlatString *s, size_t len)
}
JS_FRIEND_API(bool)
-GetPropertyKeys(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props);
+GetPropertyKeys(JSContext *cx, JS::HandleObject obj, unsigned flags, JS::AutoIdVector *props);
JS_FRIEND_API(bool)
AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others);
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 24f8fd20c1be..76f6db09c5f2 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2063,6 +2063,33 @@ js::CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
return cloneRoot;
}
+/*
+ * Return an atom for use as the name of a builtin method with the given
+ * property id.
+ *
+ * Function names are always strings. If id is the well-known @@iterator
+ * symbol, this returns "[Symbol.iterator]".
+ *
+ * Implements step 4 of SetFunctionName in ES6 draft rev 27 (24 Aug 2014).
+ */
+JSAtom *
+js::IdToFunctionName(JSContext *cx, HandleId id)
+{
+ if (JSID_IS_ATOM(id))
+ return JSID_TO_ATOM(id);
+
+ if (JSID_IS_SYMBOL(id)) {
+ RootedAtom desc(cx, JSID_TO_SYMBOL(id)->description());
+ StringBuffer sb(cx);
+ if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
+ return nullptr;
+ return sb.finishAtom();
+ }
+
+ RootedValue idv(cx, IdToValue(id));
+ return ToAtom(cx, idv);
+}
+
JSFunction *
js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
unsigned nargs, unsigned flags, AllocKind allocKind /* = FinalizeKind */,
@@ -2070,9 +2097,6 @@ js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
{
PropertyOp gop;
StrictPropertyOp sop;
-
- RootedFunction fun(cx);
-
if (flags & JSFUN_STUB_GSOPS) {
/*
* JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
@@ -2093,8 +2117,13 @@ js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
funFlags = JSFunction::INTERPRETED_LAZY;
else
funFlags = JSAPIToJSFunctionFlags(flags);
- RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
- fun = NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom, allocKind, newKind);
+
+ RootedAtom atom(cx, IdToFunctionName(cx, id));
+ if (!atom)
+ return nullptr;
+
+ RootedFunction fun(cx, NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom,
+ allocKind, newKind));
if (!fun)
return nullptr;
diff --git a/js/src/jsfun.h b/js/src/jsfun.h
index 82360b3fac1c..f36c90ea0370 100644
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -521,6 +521,9 @@ NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native,
JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind,
NewObjectKind newKind = GenericObject);
+extern JSAtom *
+IdToFunctionName(JSContext *cx, HandleId id);
+
extern JSFunction *
DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native,
unsigned nargs, unsigned flags,
@@ -572,7 +575,6 @@ CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
gc::AllocKind kind = JSFunction::FinalizeKind,
NewObjectKind newKindArg = GenericObject);
-
extern bool
FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *bodyStart,
size_t *bodyEnd);
@@ -664,7 +666,7 @@ js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
extern bool
js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
-extern JSObject*
+extern JSObject *
js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg,
js::Value *boundArgs, unsigned argslen);
diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp
index a03038b65d15..f64dc2f5a872 100644
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2264,6 +2264,8 @@ types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
* Sub2 lets us continue to distinguish the two subclasses and any extra
* properties added to those prototype objects.
*/
+ if (script->isGenerator())
+ return false;
if (JSOp(*pc) != JSOP_NEW)
return false;
pc += JSOP_NEW_LENGTH;
diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp
index 3dc61a75b5ab..38b145918c77 100644
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -271,7 +271,7 @@ struct SortComparatorIds
#endif /* JS_MORE_DETERMINISTIC */
static bool
-Snapshot(JSContext *cx, JSObject *pobj_, unsigned flags, AutoIdVector *props)
+Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props)
{
IdSet ht(cx);
if (!ht.init(32))
@@ -300,7 +300,7 @@ Snapshot(JSContext *cx, JSObject *pobj_, unsigned flags, AutoIdVector *props)
if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps))
return false;
} else {
- if (!Proxy::keys(cx, pobj, proxyProps))
+ if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps))
return false;
}
} else {
@@ -396,7 +396,7 @@ js::VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap)
}
JS_FRIEND_API(bool)
-js::GetPropertyKeys(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector *props)
+js::GetPropertyKeys(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector *props)
{
return Snapshot(cx, obj,
flags & (JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY),
@@ -1009,9 +1009,6 @@ static const JSFunctionSpec string_iterator_methods[] = {
JS_FS_END
};
-static bool
-CloseLegacyGenerator(JSContext *cx, HandleObject genobj);
-
bool
js::ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp)
{
@@ -1058,7 +1055,14 @@ js::CloseIterator(JSContext *cx, HandleObject obj)
ni->props_cursor = ni->props_array;
}
} else if (obj->is()) {
- return CloseLegacyGenerator(cx, obj);
+ Rooted genObj(cx, &obj->as());
+ if (genObj->isClosed())
+ return true;
+ if (genObj->isRunning() || genObj->isClosing()) {
+ // Nothing sensible to do.
+ return true;
+ }
+ return LegacyGeneratorObject::close(cx, obj);
}
return true;
}
@@ -1511,506 +1515,6 @@ ForOfIterator::materializeArrayIterator()
return true;
}
-/*** Generators **********************************************************************************/
-
-template
-static void
-FinalizeGenerator(FreeOp *fop, JSObject *obj)
-{
- MOZ_ASSERT(obj->is());
- JSGenerator *gen = obj->as().getGenerator();
- MOZ_ASSERT(gen);
- // gen is open when a script has not called its close method while
- // explicitly manipulating it.
- MOZ_ASSERT(gen->state == JSGEN_NEWBORN ||
- gen->state == JSGEN_CLOSED ||
- gen->state == JSGEN_OPEN);
- // If gen->state is JSGEN_CLOSED, gen->fp may be nullptr.
- if (gen->fp)
- JS_POISON(gen->fp, JS_SWEPT_FRAME_PATTERN, sizeof(InterpreterFrame));
- JS_POISON(gen, JS_SWEPT_FRAME_PATTERN, sizeof(JSGenerator));
- fop->free_(gen);
-}
-
-static void
-MarkGeneratorFrame(JSTracer *trc, JSGenerator *gen)
-{
- gen->obj = MaybeForwarded(gen->obj.get());
- MarkObject(trc, &gen->obj, "Generator Object");
- MarkValueRange(trc,
- HeapValueify(gen->fp->generatorArgsSnapshotBegin()),
- HeapValueify(gen->fp->generatorArgsSnapshotEnd()),
- "Generator Floating Args");
- gen->fp->mark(trc);
- MarkValueRange(trc,
- HeapValueify(gen->fp->generatorSlotsSnapshotBegin()),
- HeapValueify(gen->regs.sp),
- "Generator Floating Stack");
-}
-
-static void
-GeneratorWriteBarrierPre(JSContext *cx, JSGenerator *gen)
-{
- JS::Zone *zone = cx->zone();
- if (zone->needsIncrementalBarrier())
- MarkGeneratorFrame(zone->barrierTracer(), gen);
-}
-
-static void
-GeneratorWriteBarrierPost(JSContext *cx, JSGenerator *gen)
-{
-#ifdef JSGC_GENERATIONAL
- cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(gen->obj);
-#endif
-}
-
-/*
- * Only mark generator frames/slots when the generator is not active on the
- * stack or closed. Barriers when copying onto the stack or closing preserve
- * gc invariants.
- */
-static bool
-GeneratorHasMarkableFrame(JSGenerator *gen)
-{
- return gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN;
-}
-
-/*
- * When a generator is closed, the GC things reachable from the contained frame
- * and slots become unreachable and thus require a write barrier.
- */
-static void
-SetGeneratorClosed(JSContext *cx, JSGenerator *gen)
-{
- MOZ_ASSERT(gen->state != JSGEN_CLOSED);
- if (GeneratorHasMarkableFrame(gen))
- GeneratorWriteBarrierPre(cx, gen);
- gen->state = JSGEN_CLOSED;
-
-#ifdef DEBUG
- MakeRangeGCSafe(gen->fp->generatorArgsSnapshotBegin(),
- gen->fp->generatorArgsSnapshotEnd());
- MakeRangeGCSafe(gen->fp->generatorSlotsSnapshotBegin(),
- gen->regs.sp);
- PodZero(&gen->regs, 1);
- gen->fp = nullptr;
-#endif
-}
-
-template
-static void
-TraceGenerator(JSTracer *trc, JSObject *obj)
-{
- MOZ_ASSERT(obj->is());
- JSGenerator *gen = obj->as().getGenerator();
- MOZ_ASSERT(gen);
- if (GeneratorHasMarkableFrame(gen))
- MarkGeneratorFrame(trc, gen);
-}
-
-GeneratorState::GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState)
- : RunState(cx, Generator, gen->fp->script()),
- cx_(cx),
- gen_(gen),
- futureState_(futureState),
- entered_(false)
-{ }
-
-GeneratorState::~GeneratorState()
-{
- gen_->fp->setSuspended();
-
- if (entered_)
- cx_->leaveGenerator(gen_);
-}
-
-InterpreterFrame *
-GeneratorState::pushInterpreterFrame(JSContext *cx)
-{
- /*
- * Write barrier is needed since the generator stack can be updated,
- * and it's not barriered in any other way. We need to do it before
- * gen->state changes, which can cause us to trace the generator
- * differently.
- *
- * We could optimize this by setting a bit on the generator to signify
- * that it has been marked. If this bit has already been set, there is no
- * need to mark again. The bit would have to be reset before the next GC,
- * or else some kind of epoch scheme would have to be used.
- */
- GeneratorWriteBarrierPre(cx, gen_);
- gen_->state = futureState_;
-
- gen_->fp->clearSuspended();
-
- cx->enterGenerator(gen_); /* OOM check above. */
- entered_ = true;
- return gen_->fp;
-}
-
-const Class LegacyGeneratorObject::class_ = {
- "Generator",
- JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- FinalizeGenerator,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- TraceGenerator,
- JS_NULL_CLASS_SPEC,
- {
- nullptr, /* outerObject */
- nullptr, /* innerObject */
- iterator_iteratorObject,
- }
-};
-
-const Class StarGeneratorObject::class_ = {
- "Generator",
- JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- FinalizeGenerator,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- TraceGenerator,
-};
-
-/*
- * Called from the JSOP_GENERATOR case in the interpreter, with fp referring
- * to the frame by which the generator function was activated. Create a new
- * JSGenerator object, which contains its own InterpreterFrame that we populate
- * from *fp. We know that upon return, the JSOP_GENERATOR opcode will return
- * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
- * if they are non-null.
- */
-JSObject *
-js_NewGenerator(JSContext *cx, const InterpreterRegs &stackRegs)
-{
- MOZ_ASSERT(stackRegs.stackDepth() == 0);
- InterpreterFrame *stackfp = stackRegs.fp();
-
- MOZ_ASSERT(stackfp->script()->isGenerator());
-
- Rooted global(cx, &stackfp->global());
- RootedNativeObject obj(cx);
- if (stackfp->script()->isStarGenerator()) {
- RootedValue pval(cx);
- RootedObject fun(cx, stackfp->fun());
- // FIXME: This would be faster if we could avoid doing a lookup to get
- // the prototype for the instance. Bug 906600.
- if (!JSObject::getProperty(cx, fun, fun, cx->names().prototype, &pval))
- return nullptr;
- JSObject *proto = pval.isObject() ? &pval.toObject() : nullptr;
- if (!proto) {
- proto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
- if (!proto)
- return nullptr;
- }
- obj = NewNativeObjectWithGivenProto(cx, &StarGeneratorObject::class_, proto, global);
- } else {
- MOZ_ASSERT(stackfp->script()->isLegacyGenerator());
- JSObject *proto = GlobalObject::getOrCreateLegacyGeneratorObjectPrototype(cx, global);
- if (!proto)
- return nullptr;
- obj = NewNativeObjectWithGivenProto(cx, &LegacyGeneratorObject::class_, proto, global);
- }
- if (!obj)
- return nullptr;
-
- /* Load and compute stack slot counts. */
- Value *stackvp = stackfp->generatorArgsSnapshotBegin();
- unsigned vplen = stackfp->generatorArgsSnapshotEnd() - stackvp;
-
- static_assert(sizeof(InterpreterFrame) % sizeof(HeapValue) == 0,
- "The Values stored after InterpreterFrame must be aligned.");
- unsigned nvals = vplen + VALUES_PER_STACK_FRAME + stackfp->script()->nslots();
- JSGenerator *gen = obj->zone()->pod_calloc_with_extra(nvals);
- if (!gen)
- return nullptr;
-
- /* Cut up floatingStack space. */
- HeapValue *genvp = gen->stackSnapshot();
- SetValueRangeToUndefined((Value *)genvp, vplen);
-
- InterpreterFrame *genfp = reinterpret_cast(genvp + vplen);
-
- /* Initialize JSGenerator. */
- gen->obj.init(obj);
- gen->state = JSGEN_NEWBORN;
- gen->fp = genfp;
- gen->prevGenerator = nullptr;
-
- /* Copy from the stack to the generator's floating frame. */
- gen->regs.rebaseFromTo(stackRegs, *genfp);
- genfp->copyFrameAndValues(cx, (Value *)genvp, stackfp,
- stackvp, stackRegs.sp);
- genfp->setSuspended();
- obj->setPrivate(gen);
- return obj;
-}
-
-static void
-SetGeneratorClosed(JSContext *cx, JSGenerator *gen);
-
-typedef enum JSGeneratorOp {
- JSGENOP_NEXT,
- JSGENOP_SEND,
- JSGENOP_THROW,
- JSGENOP_CLOSE
-} JSGeneratorOp;
-
-/*
- * Start newborn or restart yielding generator and perform the requested
- * operation inside its frame.
- */
-static bool
-SendToGenerator(JSContext *cx, JSGeneratorOp op, HandleObject obj,
- JSGenerator *gen, HandleValue arg, GeneratorKind generatorKind,
- MutableHandleValue rval)
-{
- MOZ_ASSERT(generatorKind == LegacyGenerator || generatorKind == StarGenerator);
-
- if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NESTING_GENERATOR);
- return false;
- }
-
- JSGeneratorState futureState;
- MOZ_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
- switch (op) {
- case JSGENOP_NEXT:
- case JSGENOP_SEND:
- if (gen->state == JSGEN_OPEN) {
- /*
- * Store the argument to send as the result of the yield
- * expression. The generator stack is not barriered, so we need
- * write barriers here.
- */
- HeapValue::writeBarrierPre(gen->regs.sp[-1]);
- gen->regs.sp[-1] = arg;
- HeapValue::writeBarrierPost(gen->regs.sp[-1], &gen->regs.sp[-1]);
- }
- futureState = JSGEN_RUNNING;
- break;
-
- case JSGENOP_THROW:
- cx->setPendingException(arg);
- futureState = JSGEN_RUNNING;
- break;
-
- default:
- MOZ_ASSERT(op == JSGENOP_CLOSE);
- MOZ_ASSERT(generatorKind == LegacyGenerator);
- cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
- futureState = JSGEN_CLOSING;
- break;
- }
-
- bool ok;
- {
- GeneratorState state(cx, gen, futureState);
- ok = RunScript(cx, state);
- if (!ok && gen->state == JSGEN_CLOSED)
- return false;
- }
-
- if (gen->fp->isYielding()) {
- /*
- * Yield is ordinarily infallible, but ok can be false here if a
- * Debugger.Frame.onPop hook fails.
- */
- MOZ_ASSERT(gen->state == JSGEN_RUNNING);
- MOZ_ASSERT(op != JSGENOP_CLOSE);
- gen->fp->clearYielding();
- gen->state = JSGEN_OPEN;
- GeneratorWriteBarrierPost(cx, gen);
- rval.set(gen->fp->returnValue());
- return ok;
- }
-
- if (ok) {
- if (generatorKind == StarGenerator) {
- // Star generators return a {value:FOO, done:true} object.
- rval.set(gen->fp->returnValue());
- } else {
- MOZ_ASSERT(generatorKind == LegacyGenerator);
-
- // Otherwise we discard the return value and throw a StopIteration
- // if needed.
- rval.setUndefined();
- if (op != JSGENOP_CLOSE)
- ok = ThrowStopIteration(cx);
- }
- }
-
- SetGeneratorClosed(cx, gen);
- return ok;
-}
-
-MOZ_ALWAYS_INLINE bool
-star_generator_next(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
- JSGenerator *gen = thisObj->as().getGenerator();
-
- if (gen->state == JSGEN_CLOSED) {
- RootedObject obj(cx, CreateItrResultObject(cx, JS::UndefinedHandleValue, true));
- if (!obj)
- return false;
- args.rval().setObject(*obj);
- return true;
- }
-
- return SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0), StarGenerator,
- args.rval());
-}
-
-MOZ_ALWAYS_INLINE bool
-star_generator_throw(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSGenerator *gen = thisObj->as().getGenerator();
- if (gen->state == JSGEN_CLOSED) {
- cx->setPendingException(args.get(0));
- return false;
- }
-
- return SendToGenerator(cx, JSGENOP_THROW, thisObj, gen, args.get(0), StarGenerator,
- args.rval());
-}
-
-MOZ_ALWAYS_INLINE bool
-legacy_generator_next(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSGenerator *gen = thisObj->as().getGenerator();
- if (gen->state == JSGEN_CLOSED)
- return ThrowStopIteration(cx);
-
- return SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0), LegacyGenerator,
- args.rval());
-}
-
-MOZ_ALWAYS_INLINE bool
-legacy_generator_throw(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSGenerator *gen = thisObj->as().getGenerator();
- if (gen->state == JSGEN_CLOSED) {
- cx->setPendingException(args.length() >= 1 ? args[0] : UndefinedValue());
- return false;
- }
-
- return SendToGenerator(cx, JSGENOP_THROW, thisObj, gen, args.get(0), LegacyGenerator,
- args.rval());
-}
-
-static bool
-CloseLegacyGenerator(JSContext *cx, HandleObject obj, MutableHandleValue rval)
-{
- MOZ_ASSERT(obj->is());
-
- JSGenerator *gen = obj->as().getGenerator();
-
- if (gen->state == JSGEN_CLOSED) {
- rval.setUndefined();
- return true;
- }
-
- if (gen->state == JSGEN_NEWBORN) {
- SetGeneratorClosed(cx, gen);
- rval.setUndefined();
- return true;
- }
-
- return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JS::UndefinedHandleValue, LegacyGenerator,
- rval);
-}
-
-static bool
-CloseLegacyGenerator(JSContext *cx, HandleObject obj)
-{
- RootedValue rval(cx);
- return CloseLegacyGenerator(cx, obj, &rval);
-}
-
-MOZ_ALWAYS_INLINE bool
-legacy_generator_close(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- return CloseLegacyGenerator(cx, thisObj, args.rval());
-}
-
-template
-MOZ_ALWAYS_INLINE bool
-IsObjectOfType(HandleValue v)
-{
- return v.isObject() && v.toObject().is();
-}
-
-template
-static bool
-NativeMethod(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod, Impl>(cx, args);
-}
-
-#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
-#define JS_METHOD(name, T, impl, len, attrs) JS_FN(name, (NativeMethod), len, attrs)
-
-static const JSFunctionSpec star_generator_methods[] = {
- JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
- JS_METHOD("next", StarGeneratorObject, star_generator_next, 1, 0),
- JS_METHOD("throw", StarGeneratorObject, star_generator_throw, 1, 0),
- JS_FS_END
-};
-
-static const JSFunctionSpec legacy_generator_methods[] = {
- JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0),
- // "send" is an alias for "next".
- JS_METHOD("next", LegacyGeneratorObject, legacy_generator_next, 1, JSPROP_ROPERM),
- JS_METHOD("send", LegacyGeneratorObject, legacy_generator_next, 1, JSPROP_ROPERM),
- JS_METHOD("throw", LegacyGeneratorObject, legacy_generator_throw, 1, JSPROP_ROPERM),
- JS_METHOD("close", LegacyGeneratorObject, legacy_generator_close, 0, JSPROP_ROPERM),
- JS_FS_END
-};
-
-static JSObject*
-NewSingletonObjectWithObjectPrototype(JSContext *cx, Handle global)
-{
- JSObject *proto = global->getOrCreateObjectPrototype(cx);
- if (!proto)
- return nullptr;
- return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global, SingletonObject);
-}
-
-static JSObject*
-NewSingletonObjectWithFunctionPrototype(JSContext *cx, Handle global)
-{
- JSObject *proto = global->getOrCreateFunctionPrototype(cx);
- if (!proto)
- return nullptr;
- return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global, SingletonObject);
-}
-
/* static */ bool
GlobalObject::initIteratorClasses(JSContext *cx, Handle global)
{
@@ -2063,43 +1567,6 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle global)
global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
}
- if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) {
- proto = NewSingletonObjectWithObjectPrototype(cx, global);
- if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods))
- return false;
- global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
- }
-
- if (global->getSlot(STAR_GENERATOR_OBJECT_PROTO).isUndefined()) {
- RootedObject genObjectProto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
- if (!genObjectProto)
- return false;
- if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods))
- return false;
-
- RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
- if (!genFunctionProto)
- return false;
- if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto))
- return false;
-
- RootedValue function(cx, global->getConstructor(JSProto_Function));
- if (!function.toObjectOrNull())
- return false;
- RootedAtom name(cx, cx->names().GeneratorFunction);
- RootedObject genFunction(cx, NewFunctionWithProto(cx, NullPtr(), Generator, 1,
- JSFunction::NATIVE_CTOR, global, name,
- &function.toObject()));
- if (!genFunction)
- return false;
- if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
- return false;
-
- global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
- global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
- global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
- }
-
return GlobalObject::initStopIterationClass(cx, global);
}
@@ -2128,5 +1595,7 @@ js_InitIteratorClasses(JSContext *cx, HandleObject obj)
Rooted global(cx, &obj->as());
if (!GlobalObject::initIteratorClasses(cx, global))
return nullptr;
+ if (!GlobalObject::initGeneratorClasses(cx, global))
+ return nullptr;
return global->getIteratorPrototype();
}
diff --git a/js/src/jsiter.h b/js/src/jsiter.h
index 402cef8a5a92..e9babee2ee80 100644
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -219,39 +219,6 @@ CreateItrResultObject(JSContext *cx, HandleValue value, bool done);
} /* namespace js */
-/*
- * Generator state codes.
- */
-enum JSGeneratorState
-{
- JSGEN_NEWBORN, /* not yet started */
- JSGEN_OPEN, /* started by a .next() or .send(undefined) call */
- JSGEN_RUNNING, /* currently executing via .next(), etc., call */
- JSGEN_CLOSING, /* close method is doing asynchronous return */
- JSGEN_CLOSED /* closed, cannot be started or closed again */
-};
-
-struct JSGenerator
-{
- js::HeapPtrObject obj;
- JSGeneratorState state;
- js::InterpreterRegs regs;
- JSGenerator *prevGenerator;
- js::InterpreterFrame *fp;
-#if JS_BITS_PER_WORD == 32
- uint32_t padding;
-#endif
-
- js::HeapValue *stackSnapshot() {
- static_assert(sizeof(JSGenerator) % sizeof(js::HeapValue) == 0,
- "The generator must have Value alignment for JIT access.");
- return reinterpret_cast(this + 1);
- }
-};
-
-extern JSObject *
-js_NewGenerator(JSContext *cx, const js::InterpreterRegs ®s);
-
extern JSObject *
js_InitIteratorClasses(JSContext *cx, js::HandleObject obj);
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index 9bc08a689d23..0c04f656e158 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -4250,8 +4250,6 @@ js_DumpInterpreterFrame(JSContext *cx, InterpreterFrame *start)
fprintf(stderr, " debugger");
if (i.isEvalFrame())
fprintf(stderr, " eval");
- if (!i.isJit() && i.interpFrame()->isYielding())
- fprintf(stderr, " yielding");
if (!i.isJit() && i.interpFrame()->isGeneratorFrame())
fprintf(stderr, " generator");
fputc('\n', stderr);
diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h
index 75904b4d502b..f65d48810bdd 100644
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -298,6 +298,8 @@ BytecodeFallsThrough(JSOp op)
case JSOP_DEFAULT:
case JSOP_RETURN:
case JSOP_RETRVAL:
+ case JSOP_FINALYIELD:
+ case JSOP_FINALYIELDRVAL:
case JSOP_THROW:
case JSOP_TABLESWITCH:
return false;
@@ -599,8 +601,18 @@ inline bool
FlowsIntoNext(JSOp op)
{
/* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
- return op != JSOP_RETRVAL && op != JSOP_RETURN && op != JSOP_THROW &&
- op != JSOP_GOTO && op != JSOP_RETSUB;
+ switch (op) {
+ case JSOP_RETRVAL:
+ case JSOP_RETURN:
+ case JSOP_THROW:
+ case JSOP_GOTO:
+ case JSOP_RETSUB:
+ case JSOP_FINALYIELD:
+ case JSOP_FINALYIELDRVAL:
+ return false;
+ default:
+ return true;
+ }
}
inline bool
diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h
index aa19392a910a..ae22a1b8d64e 100644
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -33,57 +33,120 @@ class RegExpGuard;
class JS_FRIEND_API(Wrapper);
/*
- * A proxy is a JSObject that implements generic behavior by providing custom
- * implementations for each object trap. The implementation for each trap is
- * provided by a C++ object stored on the proxy, known as its handler.
+ * A proxy is a JSObject with highly customizable behavior. ES6 specifies a
+ * single kind of proxy, but the customization mechanisms we use to implement
+ * ES6 Proxy objects are also useful wherever an object with weird behavior is
+ * wanted. Proxies are used to implement:
*
- * A major use case for proxies is to forward each trap to another object,
- * known as its target. The target can be an arbitrary C++ object. Not every
- * proxy has the notion of a target, however.
+ * - the scope objects used by the Debugger's frame.eval() method
+ * (see js::GetDebugScopeForFunction)
*
- * Proxy traps are grouped into fundamental and derived traps. Every proxy has
- * to at least provide implementations for the fundamental traps, but the
- * derived traps can be implemented in terms of the fundamental ones
- * BaseProxyHandler provides implementations of the derived traps in terms of
- * the (pure virtual) fundamental traps.
+ * - the khuey hack, whereby a whole compartment can be blown away
+ * even if other compartments hold references to objects in it
+ * (see js::NukeCrossCompartmentWrappers)
*
- * In addition to the normal traps, there are two models for proxy prototype
- * chains. First, proxies may opt to use the standard prototype mechanism used
- * throughout the engine. To do so, simply pass a prototype to NewProxyObject()
- * at creation time. All prototype accesses will then "just work" to treat the
- * proxy as a "normal" object. Alternatively, if instead the proxy wishes to
- * implement more complicated prototype semantics (if, for example, it wants to
- * delegate the prototype lookup to a wrapped object), it may pass Proxy::LazyProto
- * as the prototype at create time and opt in to the trapped prototype system,
- * which guarantees that their trap will be called on any and every prototype
- * chain access of the object.
+ * - XPConnect security wrappers, which protect chrome from malicious content
+ * (js/xpconnect/wrappers)
*
- * This system is implemented with two traps: {get,set}PrototypeOf. The default
- * implementation of setPrototypeOf throws a TypeError. Since it is not possible
- * to create an object without a sense of prototype chain, handler implementors
- * must provide a getPrototypeOf trap if opting in to the dynamic prototype system.
+ * - DOM objects with special property behavior, like named getters
+ * (dom/bindings/Codegen.py generates these proxies from WebIDL)
+ *
+ * - semi-transparent use of objects that live in other processes
+ * (CPOWs, implemented in js/ipc)
+ *
+ * ### Proxies and internal methods
+ *
+ * ES6 draft rev 27 (24 August 2014) specifies 14 internal methods. The runtime
+ * semantics of just about everything a script can do to an object is specified
+ * in terms of these internal methods. For example:
+ *
+ * JS code ES6 internal method that gets called
+ * --------------------------- --------------------------------
+ * obj.prop obj.[[Get]](obj, "prop")
+ * "prop" in obj obj.[[HasProperty]]("prop")
+ * new obj() obj.[[Construct]]()
+ * for (k in obj) {} obj.[[Enumerate]]()
+ *
+ * With regard to the implementation of these internal methods, there are three
+ * very different kinds of object in SpiderMonkey.
+ *
+ * 1. Native objects' internal methods are implemented in js::baseops in
+ * vm/NativeObject.cpp, with duplicate (but functionally identical)
+ * implementations scattered through the ICs and JITs.
+ *
+ * 2. Certain non-native objects have internal methods that are implemented as
+ * magical js::ObjectOps hooks. We're trying to get rid of these.
+ *
+ * 3. All other objects are proxies. A proxy's internal methods are
+ * implemented in C++, as the virtual methods of a C++ object stored on the
+ * proxy, known as its handler.
+ *
+ * This means that just about anything you do to a proxy will end up going
+ * through a C++ virtual method call. Possibly several. There's no reason the
+ * JITs and ICs can't specialize for particular proxies, based on the handler;
+ * but currently we don't do much of this, so the virtual method overhead
+ * typically is actually incurred.
+ *
+ * ### The proxy handler hierarchy
+ *
+ * A major use case for proxies is to forward each internal method call to
+ * another object, known as its target. The target can be an arbitrary JS
+ * object. Not every proxy has the notion of a target, however.
*
* To minimize code duplication, a set of abstract proxy handler classes is
- * provided, from which other handlers may inherit. These abstract classes
- * are organized in the following hierarchy:
+ * provided, from which other handlers may inherit. These abstract classes are
+ * organized in the following hierarchy:
*
- * BaseProxyHandler
- * |
- * DirectProxyHandler
- * |
- * Wrapper
+ * BaseProxyHandler
+ * |
+ * DirectProxyHandler // has a target
+ * |
+ * Wrapper // can be unwrapped, revealing target
+ * | // (see js::CheckedUnwrap)
+ * |
+ * CrossCompartmentWrapper // target is in another compartment;
+ * // implements membrane between compartments
+ *
+ * Example: Some DOM objects (including all the arraylike DOM objects) are
+ * implemented as proxies. Since these objects don't need to forward operations
+ * to any underlying JS object, DOMJSProxyHandler directly subclasses
+ * BaseProxyHandler.
+ *
+ * Gecko's security wrappers are examples of cross-compartment wrappers.
+ *
+ * ### Proxy prototype chains
+ *
+ * In addition to the normal methods, there are two models for proxy prototype
+ * chains.
+ *
+ * 1. Proxies can use the standard prototype mechanism used throughout the
+ * engine. To do so, simply pass a prototype to NewProxyObject() at
+ * creation time. All prototype accesses will then "just work" to treat the
+ * proxy as a "normal" object.
+ *
+ * 2. A proxy can implement more complicated prototype semantics (if, for
+ * example, it wants to delegate the prototype lookup to a wrapped object)
+ * by passing Proxy::LazyProto as the prototype at create time. This
+ * guarantees that the getPrototypeOf() handler method will be called every
+ * time the object's prototype chain is accessed.
+ *
+ * This system is implemented with two methods: {get,set}PrototypeOf. The
+ * default implementation of setPrototypeOf throws a TypeError. Since it is
+ * not possible to create an object without a sense of prototype chain,
+ * handlers must implement getPrototypeOf if opting in to the dynamic
+ * prototype system.
*/
/*
* BaseProxyHandler is the most generic kind of proxy handler. It does not make
* any assumptions about the target. Consequently, it does not provide any
- * default implementation for the fundamental traps. It does, however, implement
- * the derived traps in terms of the fundamental ones. This allows consumers of
- * this class to define any custom behavior they want.
+ * default implementation for most methods. As a convenience, a few high-level
+ * methods, like get() and set(), are given default implementations that work by
+ * calling the low-level methods, like getOwnPropertyDescriptor().
*
- * Important: If you add a trap here, you should probably also add a Proxy::foo
- * entry point with an AutoEnterPolicy. If you don't, you need an explicit
- * override for the trap in SecurityWrapper. See bug 945826 comment 0.
+ * Important: If you add a method here, you should probably also add a
+ * Proxy::foo entry point with an AutoEnterPolicy. If you don't, you need an
+ * explicit override for the method in SecurityWrapper. See bug 945826 comment 0.
*/
class JS_FRIEND_API(BaseProxyHandler)
{
@@ -103,9 +166,10 @@ class JS_FRIEND_API(BaseProxyHandler)
*
* - When mHasPrototype is true, the engine never calls these methods:
* getPropertyDescriptor, has, set, enumerate, iterate. Instead, for
- * these operations, it calls the "own" traps like
- * getOwnPropertyDescriptor, hasOwn, defineProperty, keys, etc., and
- * consults the prototype chain if needed.
+ * these operations, it calls the "own" methods like
+ * getOwnPropertyDescriptor, hasOwn, defineProperty,
+ * getOwnEnumerablePropertyKeys, etc., and consults the prototype chain
+ * if needed.
*
* - When mHasPrototype is true, the engine calls handler->get() only if
* handler->hasOwn() says an own property exists on the proxy. If not,
@@ -155,14 +219,14 @@ class JS_FRIEND_API(BaseProxyHandler)
return true;
}
- /* Policy enforcement traps.
+ /* Policy enforcement methods.
*
* enter() allows the policy to specify whether the caller may perform |act|
* on the proxy's |id| property. In the case when |act| is CALL, |id| is
* generally JSID_VOID.
*
* The |act| parameter to enter() specifies the action being performed.
- * If |bp| is false, the trap suggests that the caller throw (though it
+ * If |bp| is false, the method suggests that the caller throw (though it
* may still decide to squelch the error).
*
* We make these OR-able so that assertEnteredPolicy can pass a union of them.
@@ -183,34 +247,63 @@ class JS_FRIEND_API(BaseProxyHandler)
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
bool *bp) const;
- /* ES5 Harmony fundamental proxy traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const = 0;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle desc) const = 0;
- virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
- HandleId id, MutableHandle desc) const = 0;
+ /* Standard internal methods. */
+ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle desc) const = 0;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle