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 desc) const = 0; virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0; virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; + virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const = 0; - /* ES5 Harmony derived proxy traps. */ + /* + * These methods are standard, but the engine does not normally call them. + * They're opt-in. See "Proxy prototype chains" above. + * + * getPrototypeOf() crashes if called. setPrototypeOf() throws a TypeError. + */ + virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const; + virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const; + + /* + * These standard internal methods are implemented, as a convenience, so + * that ProxyHandler subclasses don't have to provide every single method. + * + * The base-class implementations work by calling getPropertyDescriptor(). + * They do not follow any standard. When in doubt, override them. + */ virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const; - virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const; virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) const; virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp) const; - virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const; - virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleValue vp) const; - /* Spidermonkey extensions. */ - virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0; + /* + * [[Call]] and [[Construct]] are standard internal methods but according + * to the spec, they are not present on every object. + * + * SpiderMonkey never calls a proxy's call()/construct() internal method + * unless isCallable()/isConstructor() returns true for that proxy. + * + * BaseProxyHandler::isCallable()/isConstructor() always return false, and + * BaseProxyHandler::call()/construct() crash if called. So if you're + * creating a kind of that is never callable, you don't have to override + * anything, but otherwise you probably want to override all four. + */ virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const; virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, + MutableHandle desc) const = 0; + virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const; + virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, + AutoIdVector &props) const; + virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, + MutableHandleValue vp) const; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const; virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const; @@ -221,8 +314,6 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) const; virtual void finalize(JSFreeOp *fop, JSObject *proxy) const; virtual void objectMoved(JSObject *proxy, const JSObject *old) const; - virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const; - virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const; // Allow proxies, wrappers in particular, to specify callability at runtime. // Note: These do not take const JSObject *, but they do in spirit. @@ -246,13 +337,13 @@ class JS_FRIEND_API(BaseProxyHandler) }; /* - * DirectProxyHandler includes a notion of a target object. All traps are + * DirectProxyHandler includes a notion of a target object. All methods are * reimplemented such that they forward their behavior to the target. This * allows consumers of this class to forward to another object as transparently * and efficiently as possible. * - * Important: If you add a trap implementation here, you probably also need to - * add an override in CrossCompartmentWrapper. If you don't, you risk + * Important: If you add a method implementation here, you probably also need + * to add an override in CrossCompartmentWrapper. If you don't, you risk * compartment mismatches. See bug 945826 comment 0. */ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler @@ -263,10 +354,7 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler : BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy) { } - /* ES5 Harmony fundamental proxy traps. */ - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; - virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle desc) const MOZ_OVERRIDE; + /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, @@ -277,33 +365,34 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - - /* ES5 Harmony derived proxy traps. */ - 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, HandleObject proxy, HandleObject receiver, - HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool keys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleValue vp) const MOZ_OVERRIDE; - - /* Spidermonkey extensions. */ 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 nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, - CallArgs args) const MOZ_OVERRIDE; - virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, - bool *bp) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const MOZ_OVERRIDE; + virtual bool has(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, HandleObject proxy, HandleObject receiver, + HandleId id, bool strict, MutableHandleValue vp) 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; + + /* SpiderMonkey extensions. */ + 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 iterate(JSContext *cx, HandleObject proxy, unsigned flags, + MutableHandleValue vp) const MOZ_OVERRIDE; + virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, + CallArgs args) const MOZ_OVERRIDE; + virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, + bool *bp) const MOZ_OVERRIDE; virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const MOZ_OVERRIDE; virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; @@ -312,8 +401,8 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE; virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const; - virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE; virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE; + virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE; }; extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr; @@ -469,8 +558,8 @@ class JS_FRIEND_API(AutoEnterPolicy) Action enteredAction; // NB: We explicitly don't track the entered action here, because sometimes - // SET traps do an implicit GET during their implementation, leading to - // spurious assertions. + // set() methods do an implicit get() during their implementation, leading + // to spurious assertions. AutoEnterPolicy *prev; void recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act); void recordLeave(); diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 8bd71076d712..a697f56842b3 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -2665,11 +2665,11 @@ ASTSerializer::generatorExpression(ParseNode *pn, MutableHandleValue dst) LOCAL_ASSERT(next->isKind(PNK_SEMI) && next->pn_kid->isKind(PNK_YIELD) && - next->pn_kid->pn_kid); + next->pn_kid->pn_left); RootedValue body(cx); - return expression(next->pn_kid->pn_kid, &body) && + return expression(next->pn_kid->pn_left, &body) && builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst); } @@ -2996,19 +2996,19 @@ ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst) case PNK_YIELD_STAR: { - MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos)); + MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); RootedValue arg(cx); - return expression(pn->pn_kid, &arg) && + return expression(pn->pn_left, &arg) && builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst); } case PNK_YIELD: { - MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos)); + MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos)); RootedValue arg(cx); - return optExpression(pn->pn_kid, &arg) && + return optExpression(pn->pn_left, &arg) && builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst); } @@ -3313,6 +3313,12 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector & ? pnbody->pn_head->pn_next : pnbody->pn_head; + // Skip over initial yield in generator. + if (pnstart && pnstart->isKind(PNK_YIELD)) { + MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD); + pnstart = pnstart->pn_next; + } + return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) && functionBody(pnstart, &pnbody->pn_pos, body); } diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 82021e7b8708..86b91ba565b6 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -46,12 +46,13 @@ class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions { /* * A wrapper is a proxy with a target object to which it generally forwards - * operations, but may restrict access to certain operations or instrument - * the trap operations in various ways. A wrapper is distinct from a Direct Proxy - * Handler in the sense that it can be "unwrapped" in C++, exposing the underlying + * operations, but may restrict access to certain operations or instrument the + * methods in various ways. A wrapper is distinct from a Direct Proxy Handler + * in the sense that it can be "unwrapped" in C++, exposing the underlying * object (Direct Proxy Handlers have an underlying target object, but don't * expect to expose this object via any kind of unwrapping operation). Callers - * should be careful to avoid unwrapping security wrappers in the wrong context. + * should be careful to avoid unwrapping security wrappers in the wrong + * context. */ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler { @@ -112,10 +113,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy) { } - /* ES5 Harmony fundamental wrapper traps. */ - virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE; - virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const MOZ_OVERRIDE; + /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, @@ -124,22 +122,28 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - - /* ES5 Harmony derived wrapper traps. */ + virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE; + virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, + MutableHandleObject protop) const MOZ_OVERRIDE; + virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, + bool *bp) const MOZ_OVERRIDE; virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; - virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags, - MutableHandleValue vp) const MOZ_OVERRIDE; - - /* Spidermonkey extensions. */ - virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE; virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE; virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const MOZ_OVERRIDE; + virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, + AutoIdVector &props) const MOZ_OVERRIDE; + virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags, + MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, @@ -151,10 +155,6 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint, MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, - MutableHandleObject protop) const MOZ_OVERRIDE; - virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, - bool *bp) const MOZ_OVERRIDE; static const CrossCompartmentWrapper singleton; static const CrossCompartmentWrapper singletonWithPrototype; @@ -177,31 +177,32 @@ class JS_FRIEND_API(SecurityWrapper) : public Base : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) { } - virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE; virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act, bool *bp) const MOZ_OVERRIDE; + + virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const MOZ_OVERRIDE; + virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE; + virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, + bool *bp) const MOZ_OVERRIDE; + virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; - virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint, - MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const MOZ_OVERRIDE; virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE; virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const MOZ_OVERRIDE; + virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint, + MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, - bool *bp) const MOZ_OVERRIDE; + // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded + // against. virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleObject callable) const MOZ_OVERRIDE; virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) const MOZ_OVERRIDE; - // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded - // against. - /* * Allow our subclasses to select the superclass behavior they want without * needing to specify an exact superclass. diff --git a/js/src/moz.build b/js/src/moz.build index c325108b42bc..d67936488d42 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -243,6 +243,7 @@ UNIFIED_SOURCES += [ 'vm/DebuggerMemory.cpp', 'vm/ErrorObject.cpp', 'vm/ForkJoin.cpp', + 'vm/GeneratorObject.cpp', 'vm/GlobalObject.cpp', 'vm/HelperThreads.cpp', 'vm/Id.cpp', diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index 3a374b58ff20..3466b7e23f32 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -165,7 +165,8 @@ js::SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handle } bool -BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const +BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, + AutoIdVector &props) const { assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); MOZ_ASSERT(props.length() == 0); @@ -204,7 +205,7 @@ BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, AutoIdVector props(cx); if ((flags & JSITER_OWNONLY) - ? !keys(cx, proxy, props) + ? !getOwnEnumerablePropertyKeys(cx, proxy, props) : !enumerate(cx, proxy, props)) { return false; } diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 3659bb5efdf4..2db55d6b5d4d 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -151,11 +151,12 @@ CrossCompartmentWrapper::set(JSContext *cx, HandleObject wrapper, HandleObject r } bool -CrossCompartmentWrapper::keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const +CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, + AutoIdVector &props) const { PIERCE(cx, wrapper, NOTHING, - Wrapper::keys(cx, wrapper, props), + Wrapper::getOwnEnumerablePropertyKeys(cx, wrapper, props), NOTHING); } diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index 2883c6f2d32c..dbd574fb4a08 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -18,10 +18,7 @@ class DeadObjectProxy : public BaseProxyHandler : BaseProxyHandler(&family) { } - /* ES5 Harmony fundamental wrapper traps. */ - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; - virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const MOZ_OVERRIDE; + /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, @@ -30,11 +27,16 @@ class DeadObjectProxy : public BaseProxyHandler AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - - /* Spidermonkey extensions. */ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; + virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, + MutableHandleObject protop) 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; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, @@ -46,8 +48,6 @@ class DeadObjectProxy : public BaseProxyHandler virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, - MutableHandleObject protop) const MOZ_OVERRIDE; static const char family; static const DeadObjectProxy singleton; diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index 6dd64d908d7e..e6e028609c61 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -218,7 +218,8 @@ DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver } bool -DirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const +DirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, + AutoIdVector &props) const { assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); RootedObject target(cx, proxy->as().target()); diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index d8b615b76057..a2003199e947 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -216,7 +216,7 @@ Proxy::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) return policy.returnValue(); if (!handler->hasPrototype()) return proxy->as().handler()->enumerate(cx, proxy, props); - if (!handler->keys(cx, proxy, props)) + if (!handler->getOwnEnumerablePropertyKeys(cx, proxy, props)) return false; AutoIdVector protoProps(cx); INVOKE_ON_PROTOTYPE(cx, handler, proxy, @@ -341,14 +341,14 @@ Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id } bool -Proxy::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) +Proxy::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) { JS_CHECK_RECURSION(cx, return false); const BaseProxyHandler *handler = proxy->as().handler(); AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true); if (!policy.allowed()) return policy.returnValue(); - return handler->keys(cx, proxy, props); + return handler->getOwnEnumerablePropertyKeys(cx, proxy, props); } bool @@ -372,7 +372,7 @@ Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleV AutoIdVector props(cx); // The other Proxy::foo methods do the prototype-aware work for us here. if ((flags & JSITER_OWNONLY) - ? !Proxy::keys(cx, proxy, props) + ? !Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props) : !Proxy::enumerate(cx, proxy, props)) { return false; } diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 90e36fec996a..9f9262cedd41 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -18,19 +18,14 @@ class RegExpGuard; /* * Dispatch point for handlers that executes the appropriate C++ or scripted traps. * - * Important: All proxy traps need either (a) an AutoEnterPolicy in their + * Important: All proxy methods need either (a) an AutoEnterPolicy in their * Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug * 945826 comment 0. */ class Proxy { public: - /* ES5 Harmony fundamental proxy traps. */ - static bool preventExtensions(JSContext *cx, HandleObject proxy); - static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle desc); - static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandleValue vp); + /* Standard internal methods. */ static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc); static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, @@ -40,21 +35,27 @@ class Proxy static bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props); - - /* ES5 Harmony derived proxy traps. */ + static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible); + static bool preventExtensions(JSContext *cx, HandleObject proxy); + static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); + static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); - static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp); static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp); - static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props); - static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp); - - /* Spidermonkey extensions. */ - static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible); static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args); static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args); + + /* SpiderMonkey extensions. */ + static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, + MutableHandle desc); + static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, + MutableHandleValue vp); + static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); + static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, + AutoIdVector &props); + static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp); static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args); static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp); static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx); @@ -63,8 +64,6 @@ class Proxy static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g); static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp); static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); - static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); - static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable); static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 8fed01f208e6..31c74655cb13 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -172,7 +172,8 @@ ReportInvalidTrapResult(JSContext *cx, JSObject *proxy, JSAtom *atom) js::NullPtr(), bytes.ptr()); } -// This function is shared between ownPropertyKeys, enumerate, and keys +// This function is shared between ownPropertyKeys, enumerate, and +// getOwnEnumerablePropertyKeys. static bool ArrayToIdVector(JSContext *cx, HandleObject proxy, HandleObject target, HandleValue v, AutoIdVector &props, unsigned flags, JSAtom *trapName_) diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index 2918a3ca3438..9ad0418229a4 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -18,10 +18,7 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { : DirectProxyHandler(&family) { } - /* ES5 Harmony fundamental proxy traps. */ - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; - virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle desc) const MOZ_OVERRIDE; + /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, @@ -30,30 +27,34 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { 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; - - /* ES5 Harmony derived proxy traps. */ + 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 { - return BaseProxyHandler::hasOwn(cx, proxy, id, bp); - } virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE; - // Kick keys out to getOwnPropertyName and then filter. [[GetOwnProperty]] could potentially - // change the enumerability of the target's properties. - virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE { - return BaseProxyHandler::keys(cx, proxy, props); + 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; + + /* SpiderMonkey extensions. */ + 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 { + return BaseProxyHandler::hasOwn(cx, proxy, id, bp); + } + + + // Kick getOwnEnumerablePropertyKeys out to ownPropertyKeys and then + // filter. [[GetOwnProperty]] could potentially change the enumerability of + // the target's properties. + virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, + AutoIdVector &props) const MOZ_OVERRIDE { + return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props); } virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp) const MOZ_OVERRIDE; - /* ES6 Harmony traps */ - virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; - - /* Spidermonkey extensions. */ - 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 isCallable(JSObject *obj) const MOZ_OVERRIDE; virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE { // For now we maintain the broken behavior that a scripted proxy is constructable if it's diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.cpp b/js/src/proxy/ScriptedIndirectProxyHandler.cpp index c71204618610..cc3c4aeda1c7 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp @@ -302,14 +302,15 @@ ScriptedIndirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObjec } bool -ScriptedIndirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const +ScriptedIndirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, + AutoIdVector &props) const { RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy)); RootedValue value(cx); if (!GetDerivedTrap(cx, handler, cx->names().keys, &value)) return false; if (!IsCallable(value)) - return BaseProxyHandler::keys(cx, proxy, props); + return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props); return Trap(cx, handler, value, 0, nullptr, &value) && ArrayToIdVector(cx, value, props); } diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index ea0218b4f124..1f51499e48e1 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -19,10 +19,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler : BaseProxyHandler(&family) { } - /* ES5 Harmony fundamental proxy traps. */ - virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE; - virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle desc) const MOZ_OVERRIDE; + /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, @@ -31,20 +28,22 @@ class ScriptedIndirectProxyHandler : 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; - - /* ES5 Harmony derived proxy traps. */ + 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, HandleObject proxy, HandleObject receiver, HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; + + /* SpiderMonkey extensions. */ + 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 iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp) const MOZ_OVERRIDE; - - /* Spidermonkey extensions. */ - virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE; diff --git a/js/src/tests/ecma_6/Symbol/equality.js b/js/src/tests/ecma_6/Symbol/equality.js index 991db21442f0..66eaa7902adb 100644 --- a/js/src/tests/ecma_6/Symbol/equality.js +++ b/js/src/tests/ecma_6/Symbol/equality.js @@ -10,7 +10,8 @@ if (typeof Symbol === "function") { Symbol(), Symbol("Symbol.iterator"), Symbol("Symbol.iterator"), // distinct new symbol with the same description - Symbol.for("Symbol.iterator") + Symbol.for("Symbol.iterator"), + Symbol.iterator ]; // Distinct symbols are never equal to each other, even if they have the same diff --git a/js/src/tests/ecma_6/Symbol/surfaces.js b/js/src/tests/ecma_6/Symbol/surfaces.js index edbcb7758751..c318a939c57a 100644 --- a/js/src/tests/ecma_6/Symbol/surfaces.js +++ b/js/src/tests/ecma_6/Symbol/surfaces.js @@ -22,6 +22,11 @@ if (typeof Symbol === "function") { assertEq(desc.enumerable, false); assertEq(desc.writable, true); + desc = Object.getOwnPropertyDescriptor(Symbol, "iterator"); + assertEq(desc.configurable, false); + assertEq(desc.enumerable, false); + assertEq(desc.writable, false); + assertEq(Symbol.for.length, 1); assertEq(Symbol.prototype.toString.length, 0); assertEq(Symbol.prototype.valueOf.length, 0); diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 75db592e55ae..bc33dce05cf9 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -33,6 +33,7 @@ macro(callFunction, callFunction, "callFunction") \ macro(caseFirst, caseFirst, "caseFirst") \ macro(class_, class_, "class") \ + macro(close, close, "close") \ macro(Collator, Collator, "Collator") \ macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \ macro(columnNumber, columnNumber, "columnNumber") \ @@ -58,6 +59,7 @@ macro(deleteProperty, deleteProperty, "deleteProperty") \ macro(displayURL, displayURL, "displayURL") \ macro(done, done, "done") \ + macro(dotGenerator, dotGenerator, ".generator") \ macro(each, each, "each") \ macro(elementType, elementType, "elementType") \ macro(empty, empty, "") \ @@ -110,6 +112,7 @@ macro(join, join, "join") \ macro(keys, keys, "keys") \ macro(lastIndex, lastIndex, "lastIndex") \ + macro(LegacyGeneratorCloseInternal, LegacyGeneratorCloseInternal, "LegacyGeneratorCloseInternal") \ macro(length, length, "length") \ macro(let, let, "let") \ macro(line, line, "line") \ @@ -162,6 +165,7 @@ macro(prototype, prototype, "prototype") \ macro(proxy, proxy, "proxy") \ macro(Reify, Reify, "Reify") \ + macro(resumeGenerator, resumeGenerator, "resumeGenerator") \ macro(return, return_, "return") \ macro(revoke, revoke, "revoke") \ macro(scripts, scripts, "scripts") \ diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp new file mode 100644 index 000000000000..4389feed474f --- /dev/null +++ b/js/src/vm/GeneratorObject.cpp @@ -0,0 +1,329 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "vm/GeneratorObject.h" + +#include "jsatominlines.h" +#include "jsscriptinlines.h" + +#include "vm/NativeObject-inl.h" +#include "vm/Stack-inl.h" + +using namespace js; +using namespace js::types; + +JSObject * +GeneratorObject::create(JSContext *cx, const InterpreterRegs ®s) +{ + MOZ_ASSERT(regs.stackDepth() == 0); + InterpreterFrame *fp = regs.fp(); + + MOZ_ASSERT(fp->script()->isGenerator()); + + Rooted global(cx, &fp->global()); + RootedNativeObject obj(cx); + if (fp->script()->isStarGenerator()) { + RootedValue pval(cx); + RootedObject fun(cx, fp->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(fp->script()->isLegacyGenerator()); + JSObject *proto = GlobalObject::getOrCreateLegacyGeneratorObjectPrototype(cx, global); + if (!proto) + return nullptr; + obj = NewNativeObjectWithGivenProto(cx, &LegacyGeneratorObject::class_, proto, global); + } + if (!obj) + return nullptr; + + Rooted genObj(cx, &obj->as()); + + genObj->setCallee(fp->callee()); + genObj->setThisValue(fp->thisValue()); + genObj->setScopeChain(*fp->scopeChain()); + if (fp->script()->needsArgsObj()) + genObj->setArgsObj(fp->argsObj()); + genObj->clearExpressionStack(); + + return obj; +} + +bool +GeneratorObject::suspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc, + Value *vp, unsigned nvalues, GeneratorObject::SuspendKind suspendKind) +{ + Rooted genObj(cx, &obj->as()); + MOZ_ASSERT(!genObj->hasExpressionStack()); + + if (suspendKind == NORMAL && genObj->isClosing()) { + MOZ_ASSERT(genObj->is()); + RootedValue val(cx, ObjectValue(fp->callee())); + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, js::NullPtr()); + return false; + } + + genObj->setSuspendedBytecodeOffset(pc - fp->script()->code(), suspendKind == INITIAL); + genObj->setScopeChain(*fp->scopeChain()); + + if (nvalues) { + ArrayObject *stack = NewDenseCopiedArray(cx, nvalues, vp); + if (!stack) + return false; + genObj->setExpressionStack(*stack); + } + + return true; +} + +bool +GeneratorObject::finalSuspend(JSContext *cx, HandleObject obj) +{ + Rooted genObj(cx, &obj->as()); + MOZ_ASSERT(genObj->isRunning() || genObj->isClosing()); + + bool closing = genObj->isClosing(); + MOZ_ASSERT_IF(closing, genObj->is()); + genObj->setClosed(); + + if (genObj->is() && !closing) + return ThrowStopIteration(cx); + + return true; +} + +bool +GeneratorObject::resume(JSContext *cx, InterpreterActivation &activation, + HandleObject obj, HandleValue arg, GeneratorObject::ResumeKind resumeKind) +{ + Rooted genObj(cx, &obj->as()); + MOZ_ASSERT(genObj->isSuspended()); + + RootedFunction callee(cx, &genObj->callee()); + RootedValue thisv(cx, genObj->thisValue()); + RootedObject scopeChain(cx, &genObj->scopeChain()); + if (!activation.resumeGeneratorFrame(callee, thisv, scopeChain)) + return false; + + if (genObj->hasArgsObj()) + activation.regs().fp()->initArgsObj(genObj->argsObj()); + + if (genObj->hasExpressionStack()) { + uint32_t len = genObj->expressionStack().length(); + MOZ_ASSERT(activation.regs().spForStackDepth(len)); + RootedObject array(cx, &genObj->expressionStack()); + GetElements(cx, array, len, activation.regs().sp); + activation.regs().sp += len; + genObj->clearExpressionStack(); + } + + activation.regs().pc = callee->nonLazyScript()->code() + genObj->suspendedBytecodeOffset(); + + // If we are resuming a JSOP_YIELD, always push on a value, even if we are + // raising an exception. In the exception case, the stack needs to have + // something on it so that exception handling doesn't skip the catch + // blocks. See TryNoteIter::settle. + if (!genObj->isNewborn()) { + activation.regs().sp++; + MOZ_ASSERT(activation.regs().spForStackDepth(activation.regs().stackDepth())); + activation.regs().sp[-1] = arg; + } + + switch (resumeKind) { + case NEXT: + genObj->setRunning(); + return true; + + case THROW: + cx->setPendingException(arg); + if (genObj->isNewborn()) + genObj->setClosed(); + else + genObj->setRunning(); + return false; + + case CLOSE: + MOZ_ASSERT(genObj->is()); + cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING)); + genObj->setClosing(); + return false; + + default: + MOZ_CRASH("bad resumeKind"); + } +} + +bool +LegacyGeneratorObject::close(JSContext *cx, HandleObject obj) +{ + Rooted genObj(cx, &obj->as()); + + // Avoid calling back into JS unless it is necessary. + if (genObj->isClosed()) + return true; + + if (genObj->isNewborn()) { + genObj->setClosed(); + return true; + } + + RootedValue rval(cx); + + RootedValue closeValue(cx); + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().LegacyGeneratorCloseInternal, + &closeValue)) + { + return false; + } + MOZ_ASSERT(closeValue.isObject()); + MOZ_ASSERT(closeValue.toObject().is()); + + InvokeArgs args(cx); + if (!args.init(0)) + return false; + + args.setCallee(closeValue); + args.setThis(ObjectValue(*genObj)); + + return Invoke(cx, args); +} + +static JSObject * +iterator_iteratorObject(JSContext *cx, HandleObject obj, bool keysonly) +{ + return obj; +} + +const Class LegacyGeneratorObject::class_ = { + "Generator", + JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS), + JS_PropertyStub, /* addProperty */ + JS_DeletePropertyStub, /* delProperty */ + JS_PropertyStub, /* getProperty */ + JS_StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ + JS_NULL_CLASS_SPEC, + { + nullptr, /* outerObject */ + nullptr, /* innerObject */ + iterator_iteratorObject, + } +}; + +const Class StarGeneratorObject::class_ = { + "Generator", + JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS), + JS_PropertyStub, /* addProperty */ + JS_DeletePropertyStub, /* delProperty */ + JS_PropertyStub, /* getProperty */ + JS_StrictPropertyStub, /* setProperty */ + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ +}; + +static const JSFunctionSpec star_generator_methods[] = { + JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0), + JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0), + JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0), + JS_FS_END +}; + +#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) + +static const JSFunctionSpec legacy_generator_methods[] = { + JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0), + // "send" is an alias for "next". + JS_SELF_HOSTED_FN("next", "LegacyGeneratorNext", 1, JSPROP_ROPERM), + JS_SELF_HOSTED_FN("send", "LegacyGeneratorNext", 1, JSPROP_ROPERM), + JS_SELF_HOSTED_FN("throw", "LegacyGeneratorThrow", 1, JSPROP_ROPERM), + JS_SELF_HOSTED_FN("close", "LegacyGeneratorClose", 0, JSPROP_ROPERM), + JS_FS_END +}; + +#undef JSPROP_ROPERM + +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::initGeneratorClasses(JSContext *cx, Handle global) +{ + if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) { + RootedObject proto(cx, 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 true; +} diff --git a/js/src/vm/GeneratorObject.h b/js/src/vm/GeneratorObject.h index 889933e3cce3..c69d0729bcb7 100644 --- a/js/src/vm/GeneratorObject.h +++ b/js/src/vm/GeneratorObject.h @@ -7,26 +7,199 @@ #ifndef vm_GeneratorObject_h #define vm_GeneratorObject_h +#include "jscntxt.h" #include "jsobj.h" +#include "vm/ArgumentsObject.h" +#include "vm/ArrayObject.h" +#include "vm/Stack.h" + namespace js { -class LegacyGeneratorObject : public NativeObject +class GeneratorObject : public NativeObject { - public: - static const Class class_; + static const int32_t MAX_BYTECODE_OFFSET = INT32_MAX >> 1; - JSGenerator *getGenerator() { return static_cast(getPrivate()); } + public: + enum { + CALLEE_SLOT = 0, + THIS_SLOT, + SCOPE_CHAIN_SLOT, + ARGS_OBJ_SLOT, + EXPRESSION_STACK_SLOT, + BYTECODE_OFFSET_SLOT, + RESERVED_SLOTS + }; + + enum SuspendKind { INITIAL, NORMAL, FINAL }; + enum ResumeKind { NEXT, THROW, CLOSE }; + + static inline ResumeKind getResumeKind(jsbytecode *pc) { + MOZ_ASSERT(*pc == JSOP_RESUME); + unsigned arg = GET_UINT16(pc); + MOZ_ASSERT(arg <= CLOSE); + return static_cast(arg); + } + + static inline ResumeKind getResumeKind(ExclusiveContext *cx, JSAtom *atom) { + if (atom == cx->names().next) + return NEXT; + if (atom == cx->names().throw_) + return THROW; + MOZ_ASSERT(atom == cx->names().close); + return CLOSE; + } + + static JSObject *create(JSContext *cx, const InterpreterRegs ®s); + + static bool suspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc, + Value *vp, unsigned nvalues, SuspendKind kind); + + static bool resume(JSContext *cx, InterpreterActivation &activation, + HandleObject obj, HandleValue arg, ResumeKind resumeKind); + + static bool initialSuspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc) { + return suspend(cx, obj, fp, pc, nullptr, 0, INITIAL); + } + + static bool normalSuspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc, + Value *vp, unsigned nvalues) { + return suspend(cx, obj, fp, pc, vp, nvalues, NORMAL); + } + + static bool finalSuspend(JSContext *cx, HandleObject obj); + + JSFunction &callee() const { + return getFixedSlot(CALLEE_SLOT).toObject().as(); + } + void setCallee(JSFunction &callee) { + setFixedSlot(CALLEE_SLOT, ObjectValue(callee)); + } + + const Value &thisValue() const { + return getFixedSlot(THIS_SLOT); + } + void setThisValue(Value &thisv) { + setFixedSlot(THIS_SLOT, thisv); + } + + JSObject &scopeChain() const { + return getFixedSlot(SCOPE_CHAIN_SLOT).toObject(); + } + void setScopeChain(JSObject &scopeChain) { + setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(scopeChain)); + } + + bool hasArgsObj() const { + return getFixedSlot(ARGS_OBJ_SLOT).isObject(); + } + ArgumentsObject &argsObj() const { + return getFixedSlot(ARGS_OBJ_SLOT).toObject().as(); + } + void setArgsObj(ArgumentsObject &argsObj) { + setFixedSlot(ARGS_OBJ_SLOT, ObjectValue(argsObj)); + } + + bool hasExpressionStack() const { + return getFixedSlot(EXPRESSION_STACK_SLOT).isObject(); + } + ArrayObject &expressionStack() const { + return getFixedSlot(EXPRESSION_STACK_SLOT).toObject().as(); + } + void setExpressionStack(ArrayObject &expressionStack) { + setFixedSlot(EXPRESSION_STACK_SLOT, ObjectValue(expressionStack)); + } + void clearExpressionStack() { + setFixedSlot(EXPRESSION_STACK_SLOT, NullValue()); + } + + // The bytecode offset slot is abused for a few purposes. It's undefined if + // it hasn't been set yet (before the initial yield), and null if the + // generator is closed. Otherwise, the lower bit is set if the generator + // is in the "suspendedStart" set, and cleared otherwise. The upper bits + // are used for the PC offset of the suspended continuation, and are zero if + // the generator is running. If the generator is in that bizarre "closing" + // state, all upper bits are set. + + bool isRunning() const { + MOZ_ASSERT(!isClosed()); + return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() == 0; + } + bool isClosing() const { + return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() == MAX_BYTECODE_OFFSET << 1; + } + bool isSuspended() const { + MOZ_ASSERT(!isClosed()); + // Note that newborn objects also count as suspended. + return !isRunning() && !isClosing(); + } + bool isNewborn() const { + MOZ_ASSERT(!isClosed()); + return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() & 0x1; + } + void setRunning() { + MOZ_ASSERT(isSuspended()); + setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value(0)); + } + void setClosing() { + MOZ_ASSERT(isSuspended()); + setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value(MAX_BYTECODE_OFFSET << 1)); + } + ptrdiff_t suspendedBytecodeOffset() const { + MOZ_ASSERT(isSuspended()); + return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() >> 1; + } + void setSuspendedBytecodeOffset(ptrdiff_t offset, bool newborn) { + MOZ_ASSERT(newborn ? getFixedSlot(BYTECODE_OFFSET_SLOT).isUndefined() : isRunning()); + MOZ_ASSERT(offset > 0 && offset < MAX_BYTECODE_OFFSET); + setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value((offset << 1) | (newborn ? 0x1 : 0))); + MOZ_ASSERT(isSuspended()); + } + bool isClosed() const { + return getFixedSlot(CALLEE_SLOT).isNull(); + } + void setClosed() { + setFixedSlot(CALLEE_SLOT, NullValue()); + setFixedSlot(THIS_SLOT, NullValue()); + setFixedSlot(SCOPE_CHAIN_SLOT, NullValue()); + setFixedSlot(ARGS_OBJ_SLOT, NullValue()); + setFixedSlot(EXPRESSION_STACK_SLOT, NullValue()); + setFixedSlot(BYTECODE_OFFSET_SLOT, NullValue()); + } }; -class StarGeneratorObject : public NativeObject +class LegacyGeneratorObject : public GeneratorObject { public: static const Class class_; - JSGenerator *getGenerator() { return static_cast(getPrivate()); } + static bool close(JSContext *cx, HandleObject obj); + + // Unlike most other methods returning boolean, if this returns false, it + // doesn't mean that an error was raised -- it just means that the object + // wasn't newborn. + static bool maybeCloseNewborn(LegacyGeneratorObject *genObj) { + if (genObj->isNewborn()) { + genObj->setClosed(); + return true; + } + return false; + } +}; + +class StarGeneratorObject : public GeneratorObject +{ + public: + static const Class class_; }; } // namespace js +template<> +inline bool +JSObject::is() const +{ + return is() || is(); +} + #endif /* vm_GeneratorObject_h */ diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 771fe315d63a..80a16064b661 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -615,6 +615,9 @@ class GlobalObject : public NativeObject static bool initIteratorClasses(JSContext *cx, Handle global); static bool initStopIterationClass(JSContext *cx, Handle global); + // Implemented in vm/GeneratorObject.cpp. + static bool initGeneratorClasses(JSContext *cx, Handle global); + // Implemented in builtin/MapObject.cpp. static bool initMapIteratorProto(JSContext *cx, Handle global); static bool initSetIteratorProto(JSContext *cx, Handle global); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 7414b15a9c08..b93281feef13 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -35,6 +35,7 @@ #include "jit/Ion.h" #include "jit/IonAnalysis.h" #include "vm/Debugger.h" +#include "vm/GeneratorObject.h" #include "vm/Opcodes.h" #include "vm/Shape.h" #include "vm/TraceLogging.h" @@ -1657,10 +1658,6 @@ CASE(JSOP_UNUSED190) CASE(JSOP_UNUSED191) CASE(JSOP_UNUSED192) CASE(JSOP_UNUSED196) -CASE(JSOP_UNUSED201) -CASE(JSOP_UNUSED205) -CASE(JSOP_UNUSED206) -CASE(JSOP_UNUSED207) CASE(JSOP_UNUSED208) CASE(JSOP_UNUSED209) CASE(JSOP_UNUSED210) @@ -1774,9 +1771,7 @@ CASE(JSOP_RETRVAL) successful_return_continuation: interpReturnOK = true; return_continuation: - if (activation.entryFrame() != REGS.fp()) - inline_return: - { + if (activation.entryFrame() != REGS.fp()) { // Stop the engine. (No details about which engine exactly, could be // interpreter, Baseline or IonMonkey.) TraceLogStopEvent(logger); @@ -1785,11 +1780,7 @@ CASE(JSOP_RETRVAL) interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK); - if (!REGS.fp()->isYielding()) - REGS.fp()->epilogue(cx); - else - probes::ExitScript(cx, script, script->functionNonDelazifying(), - REGS.fp()->hasPushedSPSFrame()); + REGS.fp()->epilogue(cx); jit_return_pop_frame: @@ -3380,32 +3371,80 @@ CASE(JSOP_GENERATOR) { MOZ_ASSERT(!cx->isExceptionPending()); REGS.fp()->initGeneratorFrame(); - REGS.pc += JSOP_GENERATOR_LENGTH; - JSObject *obj = js_NewGenerator(cx, REGS); + JSObject *obj = GeneratorObject::create(cx, REGS); if (!obj) goto error; - REGS.fp()->setReturnValue(ObjectValue(*obj)); - REGS.fp()->setYielding(); - interpReturnOK = true; - if (activation.entryFrame() != REGS.fp()) - goto inline_return; - goto exit; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_GENERATOR) + +CASE(JSOP_INITIALYIELD) +{ + MOZ_ASSERT(!cx->isExceptionPending()); + MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame()); + RootedObject &obj = rootObject0; + obj = ®S.sp[-1].toObject(); + POP_RETURN_VALUE(); + MOZ_ASSERT(REGS.stackDepth() == 0); + if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_INITIALYIELD_LENGTH)) + goto error; + goto successful_return_continuation; } CASE(JSOP_YIELD) +{ MOZ_ASSERT(!cx->isExceptionPending()); MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame()); - if (cx->innermostGenerator()->state == JSGEN_CLOSING) { - RootedValue &val = rootValue0; - val.setObject(REGS.fp()->callee()); - js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, js::NullPtr()); + RootedObject &obj = rootObject0; + obj = ®S.sp[-1].toObject(); + if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_YIELD_LENGTH, + REGS.spForStackDepth(0), REGS.stackDepth() - 2)) + { goto error; } - REGS.fp()->setReturnValue(REGS.sp[-1]); - REGS.fp()->setYielding(); - REGS.pc += JSOP_YIELD_LENGTH; - interpReturnOK = true; - goto exit; + + REGS.sp--; + POP_RETURN_VALUE(); + + goto successful_return_continuation; +} + +CASE(JSOP_RESUME) +{ + RootedObject &gen = rootObject0; + RootedValue &val = rootValue0; + val = REGS.sp[-1]; + gen = ®S.sp[-2].toObject(); + // popInlineFrame expects there to be an additional value on the stack to + // pop off, so leave "gen" on the stack. + + GeneratorObject::ResumeKind resumeKind = GeneratorObject::getResumeKind(REGS.pc); + bool ok = GeneratorObject::resume(cx, activation, gen, val, resumeKind); + SET_SCRIPT(REGS.fp()->script()); + if (!ok) + goto error; + + ADVANCE_AND_DISPATCH(0); +} + +CASE(JSOP_FINALYIELD) + REGS.fp()->setReturnValue(REGS.sp[-2]); + REGS.sp[-2] = REGS.sp[-1]; + REGS.sp--; + /* FALL THROUGH */ +CASE(JSOP_FINALYIELDRVAL) +{ + RootedObject &gen = rootObject0; + gen = ®S.sp[-1].toObject(); + REGS.sp--; + + if (!GeneratorObject::finalSuspend(cx, gen)) { + interpReturnOK = false; + goto return_continuation; + } + + goto successful_return_continuation; +} CASE(JSOP_ARRAYPUSH) { @@ -3463,11 +3502,7 @@ DEFAULT() exit: interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK); - if (!REGS.fp()->isYielding()) - REGS.fp()->epilogue(cx); - else - probes::ExitScript(cx, script, script->functionNonDelazifying(), - REGS.fp()->hasPushedSPSFrame()); + REGS.fp()->epilogue(cx); gc::MaybeVerifyBarriers(cx, true); diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 91f4206e3e51..0f92435e68cd 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -111,7 +111,6 @@ Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval); class ExecuteState; class InvokeState; -class GeneratorState; // RunState is passed to RunScript and RunScript then eiter passes it to the // interpreter or to the JITs. RunState contains all information we need to @@ -119,7 +118,7 @@ class GeneratorState; class RunState { protected: - enum Kind { Execute, Invoke, Generator }; + enum Kind { Execute, Invoke }; Kind kind_; RootedScript script_; @@ -132,7 +131,6 @@ class RunState public: bool isExecute() const { return kind_ == Execute; } bool isInvoke() const { return kind_ == Invoke; } - bool isGenerator() const { return kind_ == Generator; } ExecuteState *asExecute() const { MOZ_ASSERT(isExecute()); @@ -142,10 +140,6 @@ class RunState MOZ_ASSERT(isInvoke()); return (InvokeState *)this; } - GeneratorState *asGenerator() const { - MOZ_ASSERT(isGenerator()); - return (GeneratorState *)this; - } JS::HandleScript script() const { return script_; } @@ -158,7 +152,6 @@ class RunState RunState(const RunState &other) MOZ_DELETE; RunState(const ExecuteState &other) MOZ_DELETE; RunState(const InvokeState &other) MOZ_DELETE; - RunState(const GeneratorState &other) MOZ_DELETE; void operator=(const RunState &other) MOZ_DELETE; }; @@ -224,24 +217,6 @@ class InvokeState : public RunState } }; -// Generator script. -class GeneratorState : public RunState -{ - JSContext *cx_; - JSGenerator *gen_; - JSGeneratorState futureState_; - bool entered_; - - public: - GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState); - ~GeneratorState(); - - virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx); - virtual void setReturnValue(Value) { } - - JSGenerator *gen() const { return gen_; } -}; - extern bool RunScript(JSContext *cx, RunState &state); diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 3f8a5284b20d..99f0c39c9aae 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1551,27 +1551,61 @@ */ \ macro(JSOP_DEBUGLEAVEBLOCK, 200,"debugleaveblock", NULL, 1, 0, 0, JOF_BYTE) \ \ - macro(JSOP_UNUSED201, 201,"unused201", NULL, 1, 0, 0, JOF_BYTE) \ - \ /* - * Initializes generator frame, creates a generator, sets 'YIELDING' flag, - * stops interpretation and returns the generator. + * Initializes generator frame, creates a generator and pushes it on the + * stack. * Category: Statements * Type: Generator * Operands: - * Stack: => + * Stack: => generator */ \ - macro(JSOP_GENERATOR, 202,"generator", NULL, 1, 0, 0, JOF_BYTE) \ + macro(JSOP_GENERATOR, 201,"generator", NULL, 1, 0, 1, JOF_BYTE) \ /* - * Pops the top of stack value as 'rval1', sets 'YIELDING' flag, - * stops interpretation and returns 'rval1', pushes sent value from - * 'send()' onto the stack. + * Pops the generator from the top of the stack, suspends it and stops + * interpretation. * Category: Statements * Type: Generator * Operands: - * Stack: rval1 => rval2 + * Stack: generator => */ \ - macro(JSOP_YIELD, 203,"yield", NULL, 1, 1, 1, JOF_BYTE) \ + macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 1, 1, 0, JOF_BYTE) \ + /* + * Pops the generator and the return value 'rval1', stops interpretation and + * returns 'rval1'. Pushes sent value from 'send()' onto the stack. + * Category: Statements + * Type: Generator + * Operands: + * Stack: rval1, gen => rval2 + */ \ + macro(JSOP_YIELD, 203,"yield", NULL, 1, 2, 1, JOF_BYTE) \ + /* + * Pops the generator and the value to yield from the stack. Then suspends + * and closes the generator. + * Category: Statements + * Type: Generator + * Operands: + * Stack: gen, val => + */ \ + macro(JSOP_FINALYIELD, 204,"finalyield", NULL, 1, 2, 0, JOF_BYTE) \ + /* + * Pops the generator and suspends and closes it. Yields the value in the + * frame's return value slot. + * Category: Statements + * Type: Generator + * Operands: + * Stack: gen => + */ \ + macro(JSOP_FINALYIELDRVAL,205,"finalyieldrval",NULL, 1, 1, 0, JOF_BYTE) \ + /* + * Pops the generator and argument from the stack, pushes a new generator + * frame and resumes execution of it. Pushes the return value after the + * generator yields. + * Category: Statements + * Type: Generator + * Operands: resume kind (GeneratorObject::ResumeKind) + * Stack: gen, val => rval + */ \ + macro(JSOP_RESUME, 206,"resume", NULL, 3, 2, 1, JOF_UINT8|JOF_INVOKE) \ /* * Pops the top two values on the stack as 'obj' and 'v', pushes 'v' to * 'obj'. @@ -1582,12 +1616,8 @@ * Operands: * Stack: v, obj => */ \ - macro(JSOP_ARRAYPUSH, 204,"arraypush", NULL, 1, 2, 0, JOF_BYTE) \ + macro(JSOP_ARRAYPUSH, 207,"arraypush", NULL, 1, 2, 0, JOF_BYTE) \ \ - macro(JSOP_UNUSED205, 205, "unused205", NULL, 1, 0, 0, JOF_BYTE) \ - macro(JSOP_UNUSED206, 206, "unused206", NULL, 1, 0, 0, JOF_BYTE) \ - \ - macro(JSOP_UNUSED207, 207, "unused207", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED208, 208, "unused208", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \ diff --git a/js/src/vm/ProxyObject.h b/js/src/vm/ProxyObject.h index 1bd1b45ad974..f4a1ac48c646 100644 --- a/js/src/vm/ProxyObject.h +++ b/js/src/vm/ProxyObject.h @@ -91,7 +91,7 @@ class ProxyObject : public JSObject // friend api exposure. // Proxy classes are not allowed to have call or construct hooks directly. Their - // callability is instead decided by a trap call + // callability is instead decided by handler()->isCallable(). return clasp->isProxy() && (clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS) && clasp->trace == proxy_Trace && diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 572bd27ab374..e152394b8aee 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -414,7 +414,7 @@ namespace js { * Storage for well-known symbols. It's a separate struct from the Runtime so * that it can be shared across multiple runtimes. As in JSAtomState, each * field is a smart pointer that's immutable once initialized. - * `rt->wellKnownSymbols.iterator` is convertible to Handle. + * `rt->wellKnownSymbols->iterator` is convertible to Handle. * * Well-known symbols are never GC'd. The description() of each well-known * symbol is a permanent atom. @@ -423,10 +423,14 @@ struct WellKnownSymbols { js::ImmutableSymbolPtr iterator; - ImmutableSymbolPtr &get(size_t i) { - MOZ_ASSERT(i < JS::WellKnownSymbolLimit); + ImmutableSymbolPtr &get(size_t u) { + MOZ_ASSERT(u < JS::WellKnownSymbolLimit); ImmutableSymbolPtr *symbols = reinterpret_cast(this); - return symbols[i]; + return symbols[u]; + } + + ImmutableSymbolPtr &get(JS::SymbolCode code) { + return get(size_t(code)); } }; diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 96a4981ff9f6..6daedc7e59b2 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -748,8 +748,6 @@ SavedStacks::FrameState::FrameState(const FrameIter &iter) name(iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr), location() { - if (principals) - JS_HoldPrincipals(principals); } SavedStacks::FrameState::FrameState(const FrameState &fs) @@ -757,13 +755,10 @@ SavedStacks::FrameState::FrameState(const FrameState &fs) name(fs.name), location(fs.location) { - if (principals) - JS_HoldPrincipals(principals); } -SavedStacks::FrameState::~FrameState() { - if (principals) - JS_DropPrincipals(TlsPerThreadData.get()->runtimeFromMainThread(), principals); +SavedStacks::FrameState::~FrameState() +{ } void diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index d328265983f1..7ebde362a951 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -233,6 +233,9 @@ class SavedStacks { void trace(JSTracer *trc); + // Note: we don't have to hold/drop principals, because we're + // only alive while the stack is being walked and during this + // time the principals are kept alive by the stack itself. JSPrincipals *principals; JSAtom *name; LocationValue location; @@ -245,7 +248,7 @@ class SavedStacks { frames(cx) { } - typedef Vector FrameStateVector; + typedef Vector FrameStateVector; inline FrameStateVector *operator->() { return &frames; } inline FrameState &operator[](size_t i) { return frames[i]; } diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index fd125e7782c2..49ef141960b9 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -2149,7 +2149,6 @@ DebugScopes::addDebugScope(JSContext *cx, const ScopeIter &si, DebugScopeObject void DebugScopes::onPopCall(AbstractFramePtr frame, JSContext *cx) { - MOZ_ASSERT(!frame.isYielding()); assertSameCompartment(cx, frame); DebugScopes *scopes = cx->compartment()->debugScopes; @@ -2166,6 +2165,9 @@ DebugScopes::onPopCall(AbstractFramePtr frame, JSContext *cx) if (!frame.hasCallObj()) return; + if (frame.fun()->isGenerator()) + return; + CallObject &callobj = frame.scopeChain()->as(); scopes->liveScopes.remove(&callobj); if (ObjectWeakMap::Ptr p = scopes->proxiedScopes.lookup(&callobj)) diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a6bf2e86074f..16d532367560 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -23,6 +23,7 @@ #include "gc/Marking.h" #include "vm/Compression.h" #include "vm/ForkJoin.h" +#include "vm/GeneratorObject.h" #include "vm/Interpreter.h" #include "vm/String.h" #include "vm/TypedArrayCommon.h" @@ -655,6 +656,159 @@ intrinsic_IsStringIterator(JSContext *cx, unsigned argc, Value *vp) return true; } +static bool +intrinsic_IsStarGeneratorObject(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + args.rval().setBoolean(args[0].toObject().is()); + return true; +} + +static bool +intrinsic_StarGeneratorObjectIsClosed(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + StarGeneratorObject *genObj = &args[0].toObject().as(); + args.rval().setBoolean(genObj->isClosed()); + return true; +} + +static bool +intrinsic_IsLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + args.rval().setBoolean(args[0].toObject().is()); + return true; +} + +static bool +intrinsic_LegacyGeneratorObjectIsClosed(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + LegacyGeneratorObject *genObj = &args[0].toObject().as(); + args.rval().setBoolean(genObj->isClosed()); + return true; +} + +static bool +intrinsic_CloseNewbornLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + LegacyGeneratorObject *genObj = &args[0].toObject().as(); + args.rval().setBoolean(LegacyGeneratorObject::maybeCloseNewborn(genObj)); + return true; +} + +static bool +intrinsic_CloseClosingLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + LegacyGeneratorObject *genObj = &args[0].toObject().as(); + MOZ_ASSERT(genObj->isClosing()); + genObj->setClosed(); + return true; +} + +static bool +intrinsic_ThrowStopIteration(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 0); + + return ThrowStopIteration(cx); +} + +static bool +intrinsic_GeneratorIsRunning(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + GeneratorObject *genObj = &args[0].toObject().as(); + args.rval().setBoolean(genObj->isRunning() || genObj->isClosing()); + return true; +} + +static bool +intrinsic_GeneratorSetClosed(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + + GeneratorObject *genObj = &args[0].toObject().as(); + genObj->setClosed(); + return true; +} + +bool +CallSelfHostedNonGenericMethod(JSContext *cx, CallArgs args) +{ + // This function is called when a self-hosted method is invoked on a + // wrapper object, like a CrossCompartmentWrapper. The last argument is + // the name of the self-hosted function. The other arguments are the + // arguments to pass to this function. + + MOZ_ASSERT(args.length() > 0); + RootedPropertyName name(cx, args[args.length() - 1].toString()->asAtom().asPropertyName()); + + RootedValue selfHostedFun(cx); + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) + return false; + + MOZ_ASSERT(selfHostedFun.toObject().is()); + + InvokeArgs args2(cx); + if (!args2.init(args.length() - 1)) + return false; + + args2.setCallee(selfHostedFun); + args2.setThis(args.thisv()); + + for (size_t i = 0; i < args.length() - 1; i++) + args2[i].set(args[i]); + + if (!Invoke(cx, args2)) + return false; + + args.rval().set(args2.rval()); + return true; +} + +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); +} + static bool intrinsic_IsWeakSet(JSContext *cx, unsigned argc, Value *vp) { @@ -902,6 +1056,23 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0), JS_FN("IsStringIterator", intrinsic_IsStringIterator, 1,0), + JS_FN("IsStarGeneratorObject", intrinsic_IsStarGeneratorObject, 1,0), + JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0), + + JS_FN("IsLegacyGeneratorObject", intrinsic_IsLegacyGeneratorObject, 1,0), + JS_FN("LegacyGeneratorObjectIsClosed", intrinsic_LegacyGeneratorObjectIsClosed, 1,0), + JS_FN("CloseNewbornLegacyGeneratorObject", intrinsic_CloseNewbornLegacyGeneratorObject, 1,0), + JS_FN("CloseClosingLegacyGeneratorObject", intrinsic_CloseClosingLegacyGeneratorObject, 1,0), + JS_FN("ThrowStopIteration", intrinsic_ThrowStopIteration, 0,0), + + JS_FN("GeneratorIsRunning", intrinsic_GeneratorIsRunning, 1,0), + JS_FN("GeneratorSetClosed", intrinsic_GeneratorSetClosed, 1,0), + + JS_FN("CallLegacyGeneratorMethodIfWrapped", + (NativeMethod), 2, 0), + JS_FN("CallStarGeneratorMethodIfWrapped", + (NativeMethod), 2, 0), + JS_FN("IsWeakSet", intrinsic_IsWeakSet, 1,0), JS_FN("ForkJoin", intrinsic_ForkJoin, 5,0), diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index d13b46ac7716..78e51ef71953 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -15,6 +15,7 @@ #include "jit/BaselineFrame.h" #include "jit/RematerializedFrame.h" +#include "vm/GeneratorObject.h" #include "vm/ScopeObject.h" #include "jsobjinlines.h" @@ -326,6 +327,45 @@ InterpreterStack::pushInlineFrame(JSContext *cx, InterpreterRegs ®s, const Ca return true; } +MOZ_ALWAYS_INLINE bool +InterpreterStack::resumeGeneratorCallFrame(JSContext *cx, InterpreterRegs ®s, + HandleFunction callee, HandleValue thisv, + HandleObject scopeChain) +{ + MOZ_ASSERT(callee->isGenerator()); + RootedScript script(cx, callee->getOrCreateScript(cx)); + InterpreterFrame *prev = regs.fp(); + jsbytecode *prevpc = regs.pc; + Value *prevsp = regs.sp; + MOZ_ASSERT(prev); + + script->ensureNonLazyCanonicalFunction(cx); + + LifoAlloc::Mark mark = allocator_.mark(); + + // Include callee, |this|. + unsigned nformal = callee->nargs(); + unsigned nvals = 2 + nformal + script->nslots(); + + uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value)); + if (!buffer) + return false; + + Value *argv = reinterpret_cast(buffer) + 2; + argv[-2] = ObjectValue(*callee); + argv[-1] = thisv; + SetValueRangeToUndefined(argv, nformal); + + InterpreterFrame *fp = reinterpret_cast(argv + nformal); + InterpreterFrame::Flags flags = ToFrameFlags(INITIAL_NONE); + fp->mark_ = mark; + fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, 0, flags); + fp->resumeGeneratorFrame(scopeChain); + + regs.prepareToRun(*fp, script); + return true; +} + MOZ_ALWAYS_INLINE void InterpreterStack::popInlineFrame(InterpreterRegs ®s) { @@ -517,14 +557,6 @@ AbstractFramePtr::isGeneratorFrame() const return false; } -inline bool -AbstractFramePtr::isYielding() const -{ - if (isInterpreterFrame()) - return asInterpreterFrame()->isYielding(); - return false; -} - inline bool AbstractFramePtr::isFunctionFrame() const { @@ -809,13 +841,8 @@ InterpreterActivation::InterpreterActivation(RunState &state, JSContext *cx, , oldFrameCount_(cx->runtime()->interpreterStack().frameCount_) #endif { - if (!state.isGenerator()) { - regs_.prepareToRun(*entryFrame, state.script()); - MOZ_ASSERT(regs_.pc == state.script()->code()); - } else { - regs_ = state.asGenerator()->gen()->regs; - } - + regs_.prepareToRun(*entryFrame, state.script()); + MOZ_ASSERT(regs_.pc == state.script()->code()); MOZ_ASSERT_IF(entryFrame_->isEvalFrame(), state_.script()->isActiveEval()); } @@ -829,13 +856,6 @@ InterpreterActivation::~InterpreterActivation() MOZ_ASSERT(oldFrameCount_ == cx->runtime()->interpreterStack().frameCount_); MOZ_ASSERT_IF(oldFrameCount_ == 0, cx->runtime()->interpreterStack().allocator_.used() == 0); - if (state_.isGenerator()) { - JSGenerator *gen = state_.asGenerator()->gen(); - gen->fp->unsetPushedSPSFrame(); - gen->regs = regs_; - return; - } - if (entryFrame_) cx->runtime()->interpreterStack().releaseFrame(entryFrame_); } @@ -861,6 +881,18 @@ InterpreterActivation::popInlineFrame(InterpreterFrame *frame) cx_->asJSContext()->runtime()->interpreterStack().popInlineFrame(regs_); } +inline bool +InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue thisv, + HandleObject scopeChain) +{ + InterpreterStack &stack = cx_->asJSContext()->runtime()->interpreterStack(); + if (!stack.resumeGeneratorCallFrame(cx_->asJSContext(), regs_, callee, thisv, scopeChain)) + return false; + + MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_); + return true; +} + inline JSContext * AsmJSActivation::cx() { diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 05d232b613db..f4dc2733a027 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -92,47 +92,6 @@ InterpreterFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFram #endif } -template -void -InterpreterFrame::copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp, - const Value *othervp, Value *othersp) -{ - MOZ_ASSERT(othervp == otherfp->generatorArgsSnapshotBegin()); - MOZ_ASSERT(othersp >= otherfp->slots()); - MOZ_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots()); - - /* Copy args, InterpreterFrame, and slots. */ - const Value *srcend = otherfp->generatorArgsSnapshotEnd(); - Value *dst = vp; - for (const Value *src = othervp; src < srcend; src++, dst++) { - *dst = *src; - if (doPostBarrier) - HeapValue::writeBarrierPost(*dst, dst); - } - - *this = *otherfp; - argv_ = vp + 2; - unsetPushedSPSFrame(); - if (doPostBarrier) - writeBarrierPost(); - - srcend = othersp; - dst = slots(); - for (const Value *src = otherfp->slots(); src < srcend; src++, dst++) { - *dst = *src; - if (doPostBarrier) - HeapValue::writeBarrierPost(*dst, dst); - } -} - -/* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */ -template -void InterpreterFrame::copyFrameAndValues( - JSContext *, Value *, InterpreterFrame *, const Value *, Value *); -template -void InterpreterFrame::copyFrameAndValues( - JSContext *, Value *, InterpreterFrame *, const Value *, Value *); - void InterpreterFrame::writeBarrierPost() { @@ -265,8 +224,6 @@ InterpreterFrame::prologue(JSContext *cx) void InterpreterFrame::epilogue(JSContext *cx) { - MOZ_ASSERT(!isYielding()); - RootedScript script(cx, this->script()); probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame()); @@ -303,11 +260,12 @@ InterpreterFrame::epilogue(JSContext *cx) MOZ_ASSERT(isNonEvalFunctionFrame()); - if (fun()->isHeavyweight()) - MOZ_ASSERT_IF(hasCallObj(), + if (fun()->isHeavyweight()) { + MOZ_ASSERT_IF(hasCallObj() && !fun()->isGenerator(), scopeChain()->as().callee().nonLazyScript() == script); - else + } else { AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain()); + } if (MOZ_UNLIKELY(cx->compartment()->debugMode())) DebugScopes::onPopCall(this, cx); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index e09ba468f75c..2dcc08621784 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -19,7 +19,6 @@ #endif struct JSCompartment; -struct JSGenerator; namespace js { @@ -188,7 +187,6 @@ class AbstractFramePtr inline bool hasCallObj() const; inline bool isGeneratorFrame() const; - inline bool isYielding() const; inline bool isFunctionFrame() const; inline bool isGlobalFrame() const; inline bool isEvalFrame() const; @@ -293,17 +291,7 @@ class InterpreterFrame GENERATOR = 0x10, /* frame is associated with a generator */ CONSTRUCTING = 0x20, /* frame is for a constructor invocation */ - /* - * Generator frame state - * - * YIELDING and SUSPENDED are similar, but there are differences. After - * a generator yields, SendToGenerator immediately clears the YIELDING - * flag, but the frame will still have the SUSPENDED flag. Also, when the - * generator returns but before it's GC'ed, YIELDING is not set but - * SUSPENDED is. - */ - YIELDING = 0x40, /* Interpret dispatched JSOP_YIELD */ - SUSPENDED = 0x80, /* Generator is not running. */ + /* (0x40 and 0x80 are unused) */ /* Function prologue state */ HAS_CALL_OBJ = 0x100, /* CallObject created for heavyweight fun */ @@ -801,29 +789,13 @@ class InterpreterFrame flags_ |= GENERATOR; } - Value *generatorArgsSnapshotBegin() const { - MOZ_ASSERT(isGeneratorFrame()); - return argv() - 2; + void resumeGeneratorFrame(HandleObject scopeChain) { + MOZ_ASSERT(!isGeneratorFrame()); + MOZ_ASSERT(isNonEvalFunctionFrame()); + flags_ |= GENERATOR | HAS_CALL_OBJ | HAS_SCOPECHAIN; + scopeChain_ = scopeChain; } - Value *generatorArgsSnapshotEnd() const { - MOZ_ASSERT(isGeneratorFrame()); - return argv() + js::Max(numActualArgs(), numFormalArgs()); - } - - Value *generatorSlotsSnapshotBegin() const { - MOZ_ASSERT(isGeneratorFrame()); - return (Value *)(this + 1); - } - - enum TriggerPostBarriers { - DoPostBarrier = true, - NoPostBarrier = false - }; - template - void copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp, - const Value *othervp, Value *othersp); - /* * Other flags */ @@ -884,33 +856,6 @@ class InterpreterFrame flags_ |= PREV_UP_TO_DATE; } - bool isYielding() { - return !!(flags_ & YIELDING); - } - - void setYielding() { - flags_ |= YIELDING; - } - - void clearYielding() { - flags_ &= ~YIELDING; - } - - bool isSuspended() const { - MOZ_ASSERT(isGeneratorFrame()); - return flags_ & SUSPENDED; - } - - void setSuspended() { - MOZ_ASSERT(isGeneratorFrame()); - flags_ |= SUSPENDED; - } - - void clearSuspended() { - MOZ_ASSERT(isGeneratorFrame()); - flags_ &= ~SUSPENDED; - } - public: void mark(JSTracer *trc); void markValues(JSTracer *trc, unsigned start, unsigned end); @@ -1052,6 +997,10 @@ class InterpreterStack void popInlineFrame(InterpreterRegs ®s); + bool resumeGeneratorCallFrame(JSContext *cx, InterpreterRegs ®s, + HandleFunction callee, HandleValue thisv, + HandleObject scopeChain); + inline void purge(JSRuntime *rt); size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { @@ -1236,6 +1185,9 @@ class InterpreterActivation : public Activation InitialFrameFlags initial); inline void popInlineFrame(InterpreterFrame *frame); + inline bool resumeGeneratorFrame(HandleFunction callee, HandleValue thisv, + HandleObject scopeChain); + InterpreterFrame *current() const { return regs_.fp(); } diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index d20e22b9fbe3..cd7ca1dc69b7 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -29,9 +29,11 @@ XDRBuffer::grow(size_t n) { MOZ_ASSERT(n > size_t(limit - cursor)); - const size_t MEM_BLOCK = 8192; + const size_t MIN_CAPACITY = 8192; size_t offset = cursor - base; - size_t newCapacity = JS_ROUNDUP(offset + n, MEM_BLOCK); + size_t newCapacity = mozilla::RoundUpPow2(offset + n); + if (newCapacity < MIN_CAPACITY) + newCapacity = MIN_CAPACITY; if (isUint32Overflow(newCapacity)) { js::gc::AutoSuppressGC suppressGC(cx()); JS_ReportErrorNumber(cx(), js_GetErrorMessage, nullptr, JSMSG_TOO_BIG_TO_ENCODE); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 0fe0e150ee64..a1671f760e99 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -28,7 +28,7 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 185); +static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 186); class XDRBuffer { public: diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 4540045201eb..e33736929e2a 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -715,10 +715,11 @@ xpc::SandboxProxyHandler::set(JSContext *cx, JS::Handle proxy, } bool -xpc::SandboxProxyHandler::keys(JSContext *cx, JS::Handle proxy, - AutoIdVector &props) const +xpc::SandboxProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, + JS::Handle proxy, + AutoIdVector &props) const { - return BaseProxyHandler::keys(cx, proxy, props); + return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props); } bool diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 03ae0e5c8fae..31fe8c45b408 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -145,6 +145,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 var version = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).version; var isNightlyBuild = version.endsWith("a1"); var isReleaseBuild = !version.contains("a"); + const jsHasSymbols = typeof Symbol === "function"; var gPrototypeProperties = {}; gPrototypeProperties['Date'] = ["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear", @@ -197,19 +198,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 ["constructor", "toSource", "toString", "apply", "call", "bind", "isGenerator", "length", "name", "arguments", "caller"]; + // Sort an array that may contain symbols as well as strings. + function sortProperties(arr) { + function sortKey(prop) { + return typeof prop + ":" + prop.toString(); + } + arr.sort((a, b) => sortKey(a) < sortKey(b) ? -1 : +1); + } + // Sort all the lists so we don't need to mutate them later (or copy them // again to sort them). for (var c of Object.keys(gPrototypeProperties)) - gPrototypeProperties[c].sort(); + sortProperties(gPrototypeProperties[c]); function filterOut(array, props) { return array.filter(p => props.indexOf(p) == -1); } - function appendUnique(array, vals) { - filterOut(vals, array).forEach(v => array.push(v)); - } - function isTypedArrayClass(classname) { return typedArrayClasses.indexOf(classname) >= 0; } @@ -267,6 +272,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 gPrototypeProperties[classname].filter(id => typeof id === "string").toSource(), "A property on the " + classname + " prototype has changed! You need a security audit from an XPConnect peer"); + if (jsHasSymbols) { + is(Object.getOwnPropertySymbols(localProto).map(uneval).sort().toSource(), + gPrototypeProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(), + "A symbol-keyed property on the " + classname + + " prototype has been changed! You need a security audit from an XPConnect peer"); + } let protoProps = filterOut(desiredProtoProps, propsToSkip); let protoCallables = protoProps.filter(name => propertyIsGetter(localProto, name, classname) || @@ -280,6 +291,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 testProtoCallables(protoCallables, xray, xrayProto, localProto); is(Object.getOwnPropertyNames(xrayProto).sort().toSource(), protoProps.toSource(), "getOwnPropertyNames works"); + if (jsHasSymbols) { + is(Object.getOwnPropertySymbols(xrayProto).map(uneval).sort().toSource(), + gPrototypeProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(), + protoProps.toSource(), "getOwnPropertySymbols works"); + } is(xrayProto.constructor, iwin[classname], "constructor property works"); @@ -303,26 +319,35 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 is(d.toLocaleString('de-DE'), d.wrappedJSObject.toLocaleString('de-DE'), "Results match"); } + var uniqueSymbol; + function testObject() { testXray('Object', Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(new iwin.Object())), new iwin.Object(), []); // Construct an object full of tricky things. + let symbolProps = ''; + if (jsHasSymbols) { + uniqueSymbol = iwin.eval('var uniqueSymbol = Symbol("uniqueSymbol"); uniqueSymbol'); + symbolProps = `, [uniqueSymbol]: 43, + [Symbol.for("registrySymbolProp")]: 44`; + } var trickyObject = - iwin.eval('new Object({ \ - primitiveProp: 42, objectProp: { foo: 2 }, \ - xoProp: top.location, hasOwnProperty: 10, \ - get getterProp() { return 2; }, \ - set setterProp(x) { }, \ - get getterSetterProp() { return 3; }, \ - set getterSetterProp(x) { }, \ - callableProp: function() { }, \ - nonXrayableProp: new WeakMap() })'); + iwin.eval(`new Object({ + primitiveProp: 42, objectProp: { foo: 2 }, + xoProp: top.location, hasOwnProperty: 10, + get getterProp() { return 2; }, + set setterProp(x) { }, + get getterSetterProp() { return 3; }, + set getterSetterProp(x) { }, + callableProp: function() { }, + nonXrayableProp: new WeakMap() + ${symbolProps} + })`); testTrickyObject(trickyObject); - } -function testArray() { + function testArray() { // The |length| property is generally very weird, especially with respect // to its behavior on the prototype. Array.prototype is actually an Array // instance, and therefore has a vestigial .length. But we don't want to @@ -332,18 +357,25 @@ function testArray() { let propsToSkip = ['length']; testXray('Array', new iwin.Array(20), new iwin.Array(), propsToSkip); + let symbolProps = ''; + if (jsHasSymbols) { + uniqueSymbol = iwin.eval('var uniqueSymbol = Symbol("uniqueSymbol"); uniqueSymbol'); + symbolProps = `trickyArray[uniqueSymbol] = 43; + trickyArray[Symbol.for("registrySymbolProp")] = 44;`; + } var trickyArray = - iwin.eval("var trickyArray = []; \ - trickyArray.primitiveProp = 42; \ - trickyArray.objectProp = { foo: 2 }; \ - trickyArray.xoProp = top.location; \ - trickyArray.hasOwnProperty = 10; \ - Object.defineProperty(trickyArray, 'getterProp', { get: function() { return 2; }}); \ - Object.defineProperty(trickyArray, 'setterProp', { set: function(x) {}}); \ - Object.defineProperty(trickyArray, 'getterSetterProp', { get: function() { return 3; }, set: function(x) {}}); \ - trickyArray.callableProp = function() {}; \ - trickyArray.nonXrayableProp = new WeakMap(); \ - trickyArray;"); + iwin.eval(`var trickyArray = []; + trickyArray.primitiveProp = 42; + trickyArray.objectProp = { foo: 2 }; + trickyArray.xoProp = top.location; + trickyArray.hasOwnProperty = 10; + Object.defineProperty(trickyArray, 'getterProp', { get: function() { return 2; }}); + Object.defineProperty(trickyArray, 'setterProp', { set: function(x) {}}); + Object.defineProperty(trickyArray, 'getterSetterProp', { get: function() { return 3; }, set: function(x) {}}); + trickyArray.callableProp = function() {}; + trickyArray.nonXrayableProp = new WeakMap(); + ${symbolProps} + trickyArray;`); // Test indexed access. trickyArray.wrappedJSObject[9] = "some indexed property"; @@ -366,11 +398,11 @@ function testArray() { is(trickyArray[1], undefined, "Frozen length forbids new properties"); testTrickyObject(trickyArray); -} + } -// Parts of this function are kind of specific to testing Object, but we factor -// it out so that we can re-use the trickyObject stuff on Arrays. -function testTrickyObject(trickyObject) { + // Parts of this function are kind of specific to testing Object, but we factor + // it out so that we can re-use the trickyObject stuff on Arrays. + function testTrickyObject(trickyObject) { // Make sure it looks right under the hood. is(trickyObject.wrappedJSObject.getterProp, 2, "Underlying object has getter"); @@ -382,11 +414,21 @@ function testTrickyObject(trickyObject) { expectedNames.push('length'); is(Object.getOwnPropertyNames(trickyObject).sort().toSource(), expectedNames.sort().toSource(), "getOwnPropertyNames should be filtered correctly"); + if (jsHasSymbols) { + var expectedSymbols = [Symbol.for("registrySymbolProp"), uniqueSymbol]; + is(Object.getOwnPropertySymbols(trickyObject).map(uneval).sort().toSource(), + expectedSymbols.map(uneval).sort().toSource(), + "getOwnPropertySymbols should be filtered correctly"); + } // Test that cloning uses the Xray view. var cloned = Cu.cloneInto(trickyObject, this); is(Object.getOwnPropertyNames(cloned).sort().toSource(), expectedNames.sort().toSource(), "structured clone should use the Xray view"); + if (jsHasSymbols) { + is(Object.getOwnPropertySymbols(cloned).map(uneval).sort().toSource(), + "[]", "structured cloning doesn't clone symbol-keyed properties yet"); + } // Test iteration and in-place modification. Beware of 'expando', which is the property // we placed on the xray proto. diff --git a/js/xpconnect/wrappers/AddonWrapper.h b/js/xpconnect/wrappers/AddonWrapper.h index 53de41c730b4..38a4573aedbf 100644 --- a/js/xpconnect/wrappers/AddonWrapper.h +++ b/js/xpconnect/wrappers/AddonWrapper.h @@ -24,21 +24,20 @@ class AddonWrapper : public Base { public: explicit MOZ_CONSTEXPR AddonWrapper(unsigned flags) : Base(flags) { } - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, - JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; - + virtual bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, + JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool set(JSContext *cx, JS::HandleObject wrapper, JS::HandleObject receiver, JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, - JS::MutableHandle desc) const MOZ_OVERRIDE; - virtual bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, + JS::Handle id, + JS::MutableHandle desc) const MOZ_OVERRIDE; static const AddonWrapper singleton; }; diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.h b/js/xpconnect/wrappers/ChromeObjectWrapper.h index 7ce222f6ca15..6dc4d06d72c8 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.h +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h @@ -28,40 +28,38 @@ class ChromeObjectWrapper : public ChromeObjectWrapperBase public: MOZ_CONSTEXPR ChromeObjectWrapper() : ChromeObjectWrapperBase(0) {} - /* Custom traps. */ - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, - JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool enter(JSContext *cx, JS::Handle wrapper, JS::Handle id, + js::Wrapper::Action act, bool *bp) const MOZ_OVERRIDE; + virtual bool defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; - virtual bool set(JSContext *cx, JS::Handle wrapper, - JS::Handle receiver, JS::Handle id, - bool strict, JS::MutableHandle vp) const MOZ_OVERRIDE; - virtual bool has(JSContext *cx, JS::Handle wrapper, JS::Handle id, bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const MOZ_OVERRIDE; - + virtual bool set(JSContext *cx, JS::Handle wrapper, + JS::Handle receiver, JS::Handle id, + bool strict, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool call(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; virtual bool construct(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; + virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, + JS::Handle id, + JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool objectClassIs(JS::Handle obj, js::ESClassValue classValue, JSContext *cx) const MOZ_OVERRIDE; - virtual bool enter(JSContext *cx, JS::Handle wrapper, JS::Handle id, - js::Wrapper::Action act, bool *bp) const MOZ_OVERRIDE; - - // NB: One might think we'd need to implement enumerate(), keys(), iterate(), - // and getPropertyKeys() here. However, ES5 built-in properties aren't - // enumerable (and SpiderMonkey's implementation seems to match the spec - // modulo Error.prototype.fileName and Error.prototype.lineNumber). Since - // we're only remapping the prototypes of standard objects, there would - // never be anything more to enumerate up the prototype chain. So we can - // actually skip these. + // NB: One might think we'd need to implement enumerate(), + // getOwnEnumerablePropertyKeys(), iterate(), and ownPropertyKeys() + // here. However, ES5 built-in properties aren't enumerable (and + // SpiderMonkey's implementation seems to match the spec modulo + // Error.prototype.fileName and Error.prototype.lineNumber). Since we're + // only remapping the prototypes of standard objects, there would never be + // anything more to enumerate up the prototype chain. So we can actually + // skip these. static const ChromeObjectWrapper singleton; }; diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index e357e02af75d..a40572fb56f9 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -112,11 +112,12 @@ FilteringWrapper::enumerate(JSContext *cx, HandleObject wrapper, template bool -FilteringWrapper::keys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const +FilteringWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, + HandleObject wrapper, + AutoIdVector &props) const { assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE); - return Base::keys(cx, wrapper, props) && + return Base::getOwnEnumerablePropertyKeys(cx, wrapper, props) && Filter(cx, wrapper, props); } diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index 2b5b72da9152..c6910e3b8d59 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -25,9 +25,9 @@ class FilteringWrapper : public Base { public: MOZ_CONSTEXPR explicit FilteringWrapper(unsigned flags) : Base(flags) {} - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, - JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool enter(JSContext *cx, JS::Handle wrapper, JS::Handle id, + js::Wrapper::Action act, bool *bp) const MOZ_OVERRIDE; + virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; @@ -35,8 +35,12 @@ class FilteringWrapper : public Base { JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool keys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const MOZ_OVERRIDE; + + virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, + JS::Handle id, + JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, + JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool iterate(JSContext *cx, JS::Handle wrapper, unsigned flags, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl, @@ -45,9 +49,6 @@ class FilteringWrapper : public Base { virtual bool defaultValue(JSContext *cx, JS::Handle obj, JSType hint, JS::MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool enter(JSContext *cx, JS::Handle wrapper, JS::Handle id, - js::Wrapper::Action act, bool *bp) const MOZ_OVERRIDE; - static const FilteringWrapper singleton; }; @@ -60,27 +61,24 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM { public: explicit CrossOriginXrayWrapper(unsigned flags); - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, - JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; - - virtual bool ownPropertyKeys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool ownPropertyKeys(JSContext *cx, JS::Handle wrapper, + JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, JS::Handle wrapper, JS::Handle id, bool *bp) const MOZ_OVERRIDE; - virtual bool enumerate(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper, JS::MutableHandleObject protop) const MOZ_OVERRIDE; + + virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, + JS::Handle id, + JS::MutableHandle desc) const MOZ_OVERRIDE; }; } diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.h b/js/xpconnect/wrappers/WaiveXrayWrapper.h index b62a7e5af040..816a53a05d80 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.h +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h @@ -17,28 +17,25 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper { public: explicit MOZ_CONSTEXPR WaiveXrayWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags) { } - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, - JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool getPrototypeOf(JSContext *cx, JS::Handle wrapper, + JS::MutableHandle protop) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle proxy, unsigned flags, - JS::MutableHandle vp) const MOZ_OVERRIDE; - - virtual bool call(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; virtual bool construct(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; + virtual bool iterate(JSContext *cx, JS::Handle proxy, unsigned flags, + JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl, JS::CallArgs args) const MOZ_OVERRIDE; - - virtual bool getPrototypeOf(JSContext *cx, JS::Handle wrapper, - JS::MutableHandle protop) const MOZ_OVERRIDE; + virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, + JS::Handle id, + JS::MutableHandle desc) const MOZ_OVERRIDE; static const WaiveXrayWrapper singleton; }; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index c72effa4e175..f5e67d3bd867 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -458,21 +458,14 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, return JS_IdToValue(cx, className, desc.value()); } - // Compute the property name we're looking for. Indexed array properties - // are handled above. We'll handle well-known symbols when we start - // supporting Symbol.iterator in bug 918828. - if (!JSID_IS_STRING(id)) - return true; - Rooted str(cx, JSID_TO_FLAT_STRING(id)); - // Grab the JSClass. We require all Xrayable classes to have a ClassSpec. const js::Class *clasp = js::GetObjectClass(target); MOZ_ASSERT(clasp->spec.defined()); - // Scan through the functions. + // Scan through the functions. Indexed array properties are handled above. const JSFunctionSpec *fsMatch = nullptr; for (const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) { - if (JS_FlatStringEqualsAscii(str, fs->name)) { + if (PropertySpecNameEqualsId(fs->name, id)) { fsMatch = fs; break; } @@ -501,7 +494,7 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper, // Scan through the properties. const JSPropertySpec *psMatch = nullptr; for (const JSPropertySpec *ps = clasp->spec.prototypeProperties; ps && ps->name; ++ps) { - if (JS_FlatStringEqualsAscii(str, ps->name)) { + if (PropertySpecNameEqualsId(ps->name, id)) { psMatch = ps; break; } @@ -632,6 +625,15 @@ JSXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, return true; } +static bool +MaybeAppend(jsid id, unsigned flags, AutoIdVector &props) +{ + MOZ_ASSERT(!(flags & JSITER_SYMBOLSONLY)); + if (!(flags & JSITER_SYMBOLS) && JSID_IS_SYMBOL(id)) + return true; + return props.append(id); +} + bool JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags, AutoIdVector &props) @@ -711,12 +713,12 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags const js::Class *clasp = js::GetObjectClass(target); MOZ_ASSERT(clasp->spec.defined()); - // Intern all the strings, and pass theme to the caller. + // Convert the method and property names to jsids and pass them to the caller. for (const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) { - RootedString str(cx, JS_InternString(cx, fs->name)); - if (!str) + jsid id; + if (!PropertySpecNameToPermanentId(cx, fs->name, &id)) return false; - if (!props.append(INTERNED_STRING_TO_JSID(cx, str))) + if (!MaybeAppend(id, flags, props)) return false; } for (const JSPropertySpec *ps = clasp->spec.prototypeProperties; ps && ps->name; ++ps) { @@ -727,10 +729,11 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags MOZ_ASSERT(ps->flags & JSPROP_NATIVE_ACCESSORS, "Self-hosted accessor added to Xrayable class - ping the XPConnect " "module owner about adding test coverage"); - RootedString str(cx, JS_InternString(cx, ps->name)); - if (!str) + + jsid id; + if (!PropertySpecNameToPermanentId(cx, ps->name, &id)) return false; - if (!props.append(INTERNED_STRING_TO_JSID(cx, str))) + if (!MaybeAppend(id, flags, props)) return false; } @@ -1978,7 +1981,7 @@ XrayWrapper::ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const { assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE); - return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props); + return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); } template @@ -2072,11 +2075,12 @@ XrayWrapper::hasOwn(JSContext *cx, HandleObject wrapper, template bool -XrayWrapper::keys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const +XrayWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, + HandleObject wrapper, + AutoIdVector &props) const { // Skip our Base if it isn't already ProxyHandler. - return js::BaseProxyHandler::keys(cx, wrapper, props); + return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props); } template diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 1d5898ac4e4d..c015ec18846a 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -404,11 +404,7 @@ class XrayWrapper : public Base { : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG, Traits::HasPrototype) { }; - /* Fundamental proxy traps. */ - virtual bool isExtensible(JSContext *cx, JS::Handle wrapper, bool *extensible) const MOZ_OVERRIDE; - virtual bool preventExtensions(JSContext *cx, JS::Handle wrapper) const MOZ_OVERRIDE; - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; + /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, JS::Handle wrapper, JS::Handle id, @@ -418,36 +414,38 @@ class XrayWrapper : public Base { virtual bool delete_(JSContext *cx, JS::Handle wrapper, JS::Handle id, bool *bp) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - - /* Derived proxy traps. */ + virtual bool isExtensible(JSContext *cx, JS::Handle wrapper, bool *extensible) const MOZ_OVERRIDE; + virtual bool preventExtensions(JSContext *cx, JS::Handle wrapper) const MOZ_OVERRIDE; + virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper, + JS::MutableHandleObject protop) const MOZ_OVERRIDE; + virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper, + JS::HandleObject proto, bool *bp) const MOZ_OVERRIDE; + virtual bool has(JSContext *cx, JS::Handle wrapper, JS::Handle id, + bool *bp) const MOZ_OVERRIDE; virtual bool get(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool set(JSContext *cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, bool strict, JS::MutableHandle vp) const MOZ_OVERRIDE; - virtual bool has(JSContext *cx, JS::Handle wrapper, JS::Handle id, - bool *bp) const MOZ_OVERRIDE; - virtual bool hasOwn(JSContext *cx, JS::Handle wrapper, JS::Handle id, - bool *bp) const MOZ_OVERRIDE; - virtual bool keys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle wrapper, unsigned flags, - JS::MutableHandle vp) const MOZ_OVERRIDE; - virtual bool call(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; virtual bool construct(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, + JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool hasOwn(JSContext *cx, JS::Handle wrapper, JS::Handle id, + bool *bp) const MOZ_OVERRIDE; + virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, + JS::AutoIdVector &props) const MOZ_OVERRIDE; + virtual bool iterate(JSContext *cx, JS::Handle wrapper, unsigned flags, + JS::MutableHandle vp) const MOZ_OVERRIDE; + virtual const char *className(JSContext *cx, JS::HandleObject proxy) const MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, JS::HandleObject wrapper, JSType hint, JS::MutableHandleValue vp) const MOZ_OVERRIDE; - virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper, - JS::MutableHandleObject protop) const MOZ_OVERRIDE; - virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper, - JS::HandleObject proto, bool *bp) const MOZ_OVERRIDE; - static const XrayWrapper singleton; private: @@ -491,25 +489,26 @@ public: { } - virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle proxy, - JS::Handle id, - JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle proxy, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; - // We just forward the derived traps to the BaseProxyHandler versions which - // implement them in terms of the fundamental traps. + // We just forward the high-level methods to the BaseProxyHandler versions + // which implement them in terms of lower-level methods. 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, JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool set(JSContext *cx, JS::Handle proxy, JS::Handle receiver, 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; + + 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; }; diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index 9288246411bd..3c483bb7eab0 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -18,6 +18,7 @@ #include "mozilla/dom/Nullable.h" #include "nsStyleStruct.h" #include "mozilla/Attributes.h" +#include "mozilla/Assertions.h" #include "mozilla/FloatingPoint.h" #include "nsCSSPseudoElements.h" #include "nsCycleCollectionParticipant.h" @@ -251,15 +252,17 @@ struct AnimationPlayerCollection : public PRCList mElementProperty == nsGkAtoms::animationsOfAfterProperty; } - nsString PseudoElement() + nsString PseudoElement() const { if (IsForElement()) { return EmptyString(); - } else if (IsForBeforePseudo()) { - return NS_LITERAL_STRING("::before"); - } else { - return NS_LITERAL_STRING("::after"); } + if (IsForBeforePseudo()) { + return NS_LITERAL_STRING("::before"); + } + MOZ_ASSERT(IsForAfterPseudo(), + "::before & ::after should be the only pseudo-elements here"); + return NS_LITERAL_STRING("::after"); } mozilla::dom::Element* GetElementToRestyle() const; diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 8b5493ae8007..7d01dc79dcab 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -35,19 +35,9 @@ using namespace mozilla; using namespace mozilla::dom; -#ifdef PR_LOGGING -static PRLogModuleInfo* -GetFontFaceSetLog() -{ - static PRLogModuleInfo* sLog; - if (!sLog) - sLog = PR_NewLogModule("fontfaceset"); - return sLog; -} -#endif /* PR_LOGGING */ - -#define LOG(args) PR_LOG(GetFontFaceSetLog(), PR_LOG_DEBUG, args) -#define LOG_ENABLED() PR_LOG_TEST(GetFontFaceSetLog(), PR_LOG_DEBUG) +#define LOG(args) PR_LOG(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG, args) +#define LOG_ENABLED() PR_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \ + PR_LOG_DEBUG) NS_IMPL_CYCLE_COLLECTION_CLASS(FontFaceSet) @@ -415,14 +405,16 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry, return NS_ERROR_OUT_OF_MEMORY; #ifdef PR_LOGGING - if (LOG_ENABLED()) { + if (PR_LOG_TEST(nsFontFaceLoader::GetFontDownloaderLog(), + PR_LOG_DEBUG)) { nsAutoCString fontURI, referrerURI; aFontFaceSrc->mURI->GetSpec(fontURI); if (aFontFaceSrc->mReferrer) aFontFaceSrc->mReferrer->GetSpec(referrerURI); - LOG(("fontdownloader (%p) download start - font uri: (%s) " - "referrer uri: (%s)\n", - fontLoader.get(), fontURI.get(), referrerURI.get())); + PR_LOG(nsFontFaceLoader::GetFontDownloaderLog(), PR_LOG_DEBUG, + ("fontdownloader (%p) download start - font uri: (%s) " + "referrer uri: (%s)\n", + fontLoader.get(), fontURI.get(), referrerURI.get())); } #endif @@ -613,6 +605,13 @@ FontFaceSet::UpdateRules(const nsTArray& aRules) // local rules have been rebuilt, so clear the flag mUserFontSet->mLocalRulesUsed = false; +#if PR_LOGGING + LOG(("userfonts (%p) userfont rules update (%s) rule count: %d", + mUserFontSet.get(), + (modified ? "modified" : "not modified"), + mRuleFaces.Length())); +#endif + return modified; } @@ -1046,13 +1045,13 @@ FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry, break; } } - message.AppendLiteral("\nsource: "); + message.AppendLiteral(" source: "); message.Append(fontURI); #ifdef PR_LOGGING - if (PR_LOG_TEST(GetFontFaceSetLog(), PR_LOG_DEBUG)) { - PR_LOG(GetFontFaceSetLog(), PR_LOG_DEBUG, - ("userfonts (%p) %s", this, message.get())); + if (PR_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG)) { + PR_LOG(gfxUserFontSet::GetUserFontsLog(), PR_LOG_DEBUG, + ("userfonts (%p) %s", mUserFontSet.get(), message.get())); } #endif diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp index 77535b9ebf87..12bb2e1d8baf 100644 --- a/layout/style/nsFontFaceLoader.cpp +++ b/layout/style/nsFontFaceLoader.cpp @@ -26,8 +26,8 @@ using namespace mozilla; #ifdef PR_LOGGING -static PRLogModuleInfo* -GetFontDownloaderLog() +PRLogModuleInfo* +nsFontFaceLoader::GetFontDownloaderLog() { static PRLogModuleInfo* sLog; if (!sLog) diff --git a/layout/style/nsFontFaceLoader.h b/layout/style/nsFontFaceLoader.h index 6aaa33ea1640..e1e6d2d71cba 100644 --- a/layout/style/nsFontFaceLoader.h +++ b/layout/style/nsFontFaceLoader.h @@ -46,6 +46,10 @@ public: nsIURI* aTargetURI, nsISupports* aContext); +#ifdef PR_LOGGING + static PRLogModuleInfo* GetFontDownloaderLog(); +#endif + protected: virtual ~nsFontFaceLoader(); diff --git a/mobile/android/base/tests/testANRReporter.java b/mobile/android/base/tests/testANRReporter.java index 5856f9fdbe32..e897a93e448d 100644 --- a/mobile/android/base/tests/testANRReporter.java +++ b/mobile/android/base/tests/testANRReporter.java @@ -20,7 +20,7 @@ public class testANRReporter extends BaseTest { private static final String ANR_ACTION = "android.intent.action.ANR"; private static final String PING_DIR = "saved-telemetry-pings"; - private static final int WAIT_FOR_PING_TIMEOUT = 10000; + private static final int WAIT_FOR_PING_TIMEOUT = 60000; private static final String ANR_PATH = "/data/anr/traces.txt"; private static final String SAMPLE_ANR = "----- pid 1 at 2014-01-15 18:55:51 -----\n" @@ -159,10 +159,17 @@ public class testANRReporter extends BaseTest { mAsserter.info("Triggering second ANR", null); testContext.sendBroadcast(new Intent(anrIntent)); - mAsserter.info("Waiting for ping", null); waitForCondition(new Condition() { @Override public boolean isSatisfied() { + mAsserter.info("Waiting for ping", null); + + try { + // Sleep to allow the ANR reporter thread time to process the ANR. + Thread.sleep(1000); + } catch (final InterruptedException e) { + } + final File[] newFiles = pingDir.listFiles(); if (newFiles == null || newFiles.length == 0) { // Keep waiting. diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp index 72f560dc523e..09373e9ad403 100644 --- a/mozglue/linker/ElfLoader.cpp +++ b/mozglue/linker/ElfLoader.cpp @@ -512,7 +512,9 @@ ElfLoader::~ElfLoader() /* Release self_elf and libc */ self_elf = nullptr; +#if defined(ANDROID) libc = nullptr; +#endif /* Build up a list of all library handles with direct (external) references. * We actually skip system library handles because we want to keep at least diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h index b23f7ce361cc..d2f91af90df6 100644 --- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -597,101 +597,145 @@ NS_GetRealPort(nsIURI* aURI) } inline nsresult -NS_NewInputStreamChannel(nsIChannel **result, - nsIURI *uri, - nsIInputStream *stream, - const nsACString &contentType, - const nsACString *contentCharset) +NS_NewInputStreamChannelInternal(nsIChannel** outChannel, + nsIURI* aUri, + nsIInputStream* aStream, + const nsACString& aContentType, + const nsACString& aContentCharset, + nsINode* aRequestingNode, + nsIPrincipal* aRequestingPrincipal, + nsSecurityFlags aSecurityFlags, + nsContentPolicyType aContentPolicyType) { - nsresult rv; - nsCOMPtr isc = - do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return rv; - rv = isc->SetURI(uri); - nsresult tmp = isc->SetContentStream(stream); - if (NS_FAILED(tmp)) { - rv = tmp; - } - if (NS_FAILED(rv)) - return rv; - nsCOMPtr chan = do_QueryInterface(isc, &rv); - if (NS_FAILED(rv)) - return rv; - if (!contentType.IsEmpty()) - rv = chan->SetContentType(contentType); - if (contentCharset && !contentCharset->IsEmpty()) { - tmp = chan->SetContentCharset(*contentCharset); - if (NS_FAILED(tmp)) { - rv = tmp; - } - } - if (NS_SUCCEEDED(rv)) { - *result = nullptr; - chan.swap(*result); - } - return rv; -} + nsresult rv; + nsCOMPtr isc = + do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = isc->SetURI(aUri); + NS_ENSURE_SUCCESS(rv, rv); + rv = isc->SetContentStream(aStream); + NS_ENSURE_SUCCESS(rv, rv); -inline nsresult -NS_NewInputStreamChannel(nsIChannel **result, - nsIURI *uri, - nsIInputStream *stream, - const nsACString &contentType = EmptyCString()) -{ - return NS_NewInputStreamChannel(result, uri, stream, contentType, nullptr); -} + nsCOMPtr channel = do_QueryInterface(isc, &rv); + NS_ENSURE_SUCCESS(rv, rv); -inline nsresult -NS_NewInputStreamChannel(nsIChannel **result, - nsIURI *uri, - nsIInputStream *stream, - const nsACString &contentType, - const nsACString &contentCharset) -{ - return NS_NewInputStreamChannel(result, uri, stream, contentType, - &contentCharset); -} - -inline nsresult -NS_NewInputStreamChannel(nsIChannel **result, - nsIURI *uri, - const nsAString &data, - const nsACString &contentType, - bool isSrcdocChannel = false) -{ - - nsresult rv; - - nsCOMPtr stream; - stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); + if (!aContentType.IsEmpty()) { + rv = channel->SetContentType(aContentType); NS_ENSURE_SUCCESS(rv, rv); + } + + if (!aContentCharset.IsEmpty()) { + rv = channel->SetContentCharset(aContentCharset); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr loadInfo = + new mozilla::LoadInfo(aRequestingPrincipal, + aRequestingNode, + aSecurityFlags, + aContentPolicyType); + if (!loadInfo) { + return NS_ERROR_UNEXPECTED; + } + channel->SetLoadInfo(loadInfo); + + // If we're sandboxed, make sure to clear any owner the channel + // might already have. + if (loadInfo->GetLoadingSandboxed()) { + channel->SetOwner(nullptr); + } + + channel.forget(outChannel); + return NS_OK; +} + +inline nsresult /* NS_NewInputStreamChannelPrincipal */ +NS_NewInputStreamChannel(nsIChannel** outChannel, + nsIURI* aUri, + nsIInputStream* aStream, + nsIPrincipal* aRequestingPrincipal, + nsSecurityFlags aSecurityFlags, + nsContentPolicyType aContentPolicyType, + const nsACString& aContentType = EmptyCString(), + const nsACString& aContentCharset = EmptyCString()) +{ + return NS_NewInputStreamChannelInternal(outChannel, + aUri, + aStream, + aContentType, + aContentCharset, + nullptr, // aRequestingNode + aRequestingPrincipal, + aSecurityFlags, + aContentPolicyType); +} + +inline nsresult +NS_NewInputStreamChannelInternal(nsIChannel** outChannel, + nsIURI* aUri, + const nsAString& aData, + const nsACString& aContentType, + nsINode* aRequestingNode, + nsIPrincipal* aRequestingPrincipal, + nsSecurityFlags aSecurityFlags, + nsContentPolicyType aContentPolicyType, + bool aIsSrcdocChannel = false) +{ + nsresult rv; + nsCOMPtr stream; + stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); #ifdef MOZILLA_INTERNAL_API uint32_t len; - char* utf8Bytes = ToNewUTF8String(data, &len); + char* utf8Bytes = ToNewUTF8String(aData, &len); rv = stream->AdoptData(utf8Bytes, len); #else - char* utf8Bytes = ToNewUTF8String(data); + char* utf8Bytes = ToNewUTF8String(aData); rv = stream->AdoptData(utf8Bytes, strlen(utf8Bytes)); #endif - nsCOMPtr chan; + nsCOMPtr channel; + rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel), + aUri, + stream, + aContentType, + NS_LITERAL_CSTRING("UTF-8"), + aRequestingNode, + aRequestingPrincipal, + aSecurityFlags, + aContentPolicyType); - rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream, - contentType, NS_LITERAL_CSTRING("UTF-8")); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_SUCCESS(rv, rv); - if (isSrcdocChannel) { - nsCOMPtr inStrmChan = do_QueryInterface(chan); - NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE); - inStrmChan->SetSrcdocData(data); - } + if (aIsSrcdocChannel) { + nsCOMPtr inStrmChan = do_QueryInterface(channel); + NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE); + inStrmChan->SetSrcdocData(aData); + } + channel.forget(outChannel); + return NS_OK; +} - *result = nullptr; - chan.swap(*result); - - return NS_OK; +inline nsresult +NS_NewInputStreamChannel(nsIChannel** outChannel, + nsIURI* aUri, + const nsAString& aData, + const nsACString& aContentType, + nsIPrincipal* aRequestingPrincipal, + nsSecurityFlags aSecurityFlags, + nsContentPolicyType aContentPolicyType, + bool aIsSrcdocChannel = false) +{ + return NS_NewInputStreamChannelInternal(outChannel, + aUri, + aData, + aContentType, + nullptr, // aRequestingNode + aRequestingPrincipal, + aSecurityFlags, + aContentPolicyType, + aIsSrcdocChannel); } inline nsresult diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index deb3880a698a..ac4967b70159 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -266,6 +266,47 @@ GetBlacklistCountHistogram(DnsExpirationVariant aVariant, return DNS_BLACKLIST_COUNT_VAR_CONTROL_LOW; } +static mozilla::Telemetry::ID +GetRenewalTimeHistogram(DnsExpirationVariant aVariant) +{ + using namespace mozilla::Telemetry; + +#ifdef TTL_AVAILABLE + switch (sDnsVariant) { + case DNS_EXP_VARIANT_CONTROL: + return DNS_RENEWAL_TIME; + case DNS_EXP_VARIANT_TTL_ONLY: + return DNS_RENEWAL_TIME__TTL_ONLY_EXPT; + case DNS_EXP_VARIANT_TTL_PLUS_CONST_GRACE: + return DNS_RENEWAL_TIME__TTL_PLUS_CONST_GRACE_EXPT; + default: + MOZ_ASSERT_UNREACHABLE("Invalid variant."); + } +#endif + return DNS_RENEWAL_TIME; +} + +static mozilla::Telemetry::ID +GetRenewalTimeForTTLHistogram(DnsExpirationVariant aVariant) +{ + using namespace mozilla::Telemetry; + +#ifdef TTL_AVAILABLE + switch (sDnsVariant) { + case DNS_EXP_VARIANT_CONTROL: + MOZ_ASSERT_UNREACHABLE("No TTL for Control Expt."); + return DNS_RENEWAL_TIME; + case DNS_EXP_VARIANT_TTL_ONLY: + return DNS_RENEWAL_TIME_FOR_TTL__TTL_ONLY_EXPT; + case DNS_EXP_VARIANT_TTL_PLUS_CONST_GRACE: + return DNS_RENEWAL_TIME_FOR_TTL__TTL_PLUS_CONST_GRACE_EXPT; + default: + MOZ_ASSERT_UNREACHABLE("Invalid variant."); + } +#endif + return DNS_RENEWAL_TIME; +} + // this macro filters out any flags that are not used when constructing the // host key. the significant flags are those that would affect the resulting // host record (i.e., the flags that are passed down to PR_GetAddrInfoByName). @@ -1610,12 +1651,19 @@ nsHostResolver::ThreadFunc(void *arg) uint32_t millis = static_cast(elapsed.ToMilliseconds()); if (NS_SUCCEEDED(status)) { - Telemetry::Accumulate(!rec->addr_info_gencnt ? - Telemetry::DNS_LOOKUP_TIME : - Telemetry::DNS_RENEWAL_TIME, - millis); - } - else { + Telemetry::ID histogramID; + if (!rec->addr_info_gencnt) { + // Time for initial lookup. + histogramID = Telemetry::DNS_LOOKUP_TIME; + } else if (!getTtl) { + // Time for renewal; categorized by expiration strategy. + histogramID = GetRenewalTimeHistogram(sDnsVariant); + } else { + // Time to get TTL; categorized by expiration strategy. + histogramID = GetRenewalTimeForTTLHistogram(sDnsVariant); + } + Telemetry::Accumulate(histogramID, millis); + } else { Telemetry::Accumulate(Telemetry::DNS_FAILED_LOOKUP_TIME, millis); } diff --git a/netwerk/protocol/about/nsAboutBlank.cpp b/netwerk/protocol/about/nsAboutBlank.cpp index 95cb51862d81..930585067609 100644 --- a/netwerk/protocol/about/nsAboutBlank.cpp +++ b/netwerk/protocol/about/nsAboutBlank.cpp @@ -7,6 +7,7 @@ #include "nsStringStream.h" #include "nsDOMString.h" #include "nsNetUtil.h" +#include "nsContentUtils.h" NS_IMPL_ISUPPORTS(nsAboutBlank, nsIAboutModule) @@ -20,7 +21,12 @@ nsAboutBlank::NewChannel(nsIURI *aURI, nsIChannel **result) if (NS_FAILED(rv)) return rv; nsCOMPtr channel; - rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, in, + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), + aURI, + in, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, NS_LITERAL_CSTRING("text/html"), NS_LITERAL_CSTRING("utf-8")); if (NS_FAILED(rv)) return rv; diff --git a/netwerk/protocol/about/nsAboutBloat.cpp b/netwerk/protocol/about/nsAboutBloat.cpp index ba1a95d53b1b..65beac5b93c7 100644 --- a/netwerk/protocol/about/nsAboutBloat.cpp +++ b/netwerk/protocol/about/nsAboutBloat.cpp @@ -9,6 +9,7 @@ #ifdef NS_BUILD_REFCNT_LOGGING #include "nsAboutBloat.h" +#include "nsContentUtils.h" #include "nsStringStream.h" #include "nsDOMString.h" #include "nsIURI.h" @@ -109,7 +110,12 @@ nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result) } nsIChannel* channel = nullptr; - rv = NS_NewInputStreamChannel(&channel, aURI, inStr, + rv = NS_NewInputStreamChannel(&channel, + aURI, + inStr, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, NS_LITERAL_CSTRING("text/plain"), NS_LITERAL_CSTRING("utf-8")); if (NS_FAILED(rv)) return rv; diff --git a/netwerk/protocol/about/nsAboutCache.cpp b/netwerk/protocol/about/nsAboutCache.cpp index 75b6bbf9efbc..f2face1f32e4 100644 --- a/netwerk/protocol/about/nsAboutCache.cpp +++ b/netwerk/protocol/about/nsAboutCache.cpp @@ -9,6 +9,7 @@ #include "nsIURI.h" #include "nsCOMPtr.h" #include "nsNetUtil.h" +#include "nsContentUtils.h" #include "nsEscape.h" #include "nsAboutProtocolUtils.h" #include "nsPrintfCString.h" @@ -61,7 +62,12 @@ nsAboutCache::NewChannel(nsIURI *aURI, nsIChannel **result) mEntriesHeaderAdded = false; nsCOMPtr channel; - rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, inputStream, + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), + aURI, + inputStream, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, NS_LITERAL_CSTRING("text/html"), NS_LITERAL_CSTRING("utf-8")); if (NS_FAILED(rv)) return rv; diff --git a/netwerk/protocol/about/nsAboutCacheEntry.cpp b/netwerk/protocol/about/nsAboutCacheEntry.cpp index 74ae0f291579..5f4f2a19d0fd 100644 --- a/netwerk/protocol/about/nsAboutCacheEntry.cpp +++ b/netwerk/protocol/about/nsAboutCacheEntry.cpp @@ -14,6 +14,7 @@ #include "nsIAsyncInputStream.h" #include "nsIAsyncOutputStream.h" #include "nsAboutProtocolUtils.h" +#include "nsContentUtils.h" #include "nsInputStreamPump.h" #include "CacheFileUtils.h" #include @@ -97,7 +98,12 @@ nsAboutCacheEntry::NewChannel(nsIURI *uri, nsIChannel **result) rv = GetContentStream(uri, getter_AddRefs(stream)); if (NS_FAILED(rv)) return rv; - return NS_NewInputStreamChannel(result, uri, stream, + return NS_NewInputStreamChannel(result, + uri, + stream, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, NS_LITERAL_CSTRING("text/html"), NS_LITERAL_CSTRING("utf-8")); } diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index ff7166eeecb0..99d6c6c4efb3 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -8,6 +8,7 @@ #include "nsIIOService.h" #include "nsMimeTypes.h" #include "nsNetUtil.h" +#include "nsContentUtils.h" #include "nsIHttpHeaderVisitor.h" NS_IMPL_ADDREF(nsViewSourceChannel) @@ -85,8 +86,13 @@ nsViewSourceChannel::InitSrcdoc(nsIURI* aURI, const nsAString &aSrcdoc, NS_LITERAL_STRING("about:srcdoc")); NS_ENSURE_SUCCESS(rv, rv); - rv = NS_NewInputStreamChannel(getter_AddRefs(mChannel), inStreamURI, - aSrcdoc, NS_LITERAL_CSTRING("text/html"), + rv = NS_NewInputStreamChannel(getter_AddRefs(mChannel), + inStreamURI, + aSrcdoc, + NS_LITERAL_CSTRING("text/html"), + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, true); NS_ENSURE_SUCCESS(rv, rv); diff --git a/parser/xml/nsSAXXMLReader.cpp b/parser/xml/nsSAXXMLReader.cpp index 049cb6c12601..2a119aed1cfe 100644 --- a/parser/xml/nsSAXXMLReader.cpp +++ b/parser/xml/nsSAXXMLReader.cpp @@ -6,6 +6,7 @@ #include "nsIInputStream.h" #include "nsNetCID.h" #include "nsNetUtil.h" +#include "nsNullPrincipal.h" #include "nsIParser.h" #include "nsParserCIID.h" #include "nsStreamUtils.h" @@ -495,9 +496,18 @@ nsSAXXMLReader::ParseFromStream(nsIInputStream *aStream, rv = EnsureBaseURI(); NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr nullPrincipal = + do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr parserChannel; - rv = NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mBaseURI, - aStream, nsDependentCString(aContentType)); + rv = NS_NewInputStreamChannel(getter_AddRefs(parserChannel), + mBaseURI, + aStream, + nullPrincipal, + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, + nsDependentCString(aContentType)); if (!parserChannel || NS_FAILED(rv)) return NS_ERROR_FAILURE; diff --git a/rdf/base/nsRDFXMLParser.cpp b/rdf/base/nsRDFXMLParser.cpp index 03210658f305..fc466f3a90e2 100644 --- a/rdf/base/nsRDFXMLParser.cpp +++ b/rdf/base/nsRDFXMLParser.cpp @@ -13,6 +13,7 @@ #include "nsParserCIID.h" #include "nsStringStream.h" #include "nsNetUtil.h" +#include "nsNullPrincipal.h" static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); @@ -114,8 +115,17 @@ nsRDFXMLParser::ParseString(nsIRDFDataSource* aSink, nsIURI* aBaseURI, const nsA rv = NS_NewCStringInputStream(getter_AddRefs(stream), aString); if (NS_FAILED(rv)) return rv; + nsCOMPtr nullPrincipal = + do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr channel; - rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aBaseURI, stream, + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), + aBaseURI, + stream, + nullPrincipal, + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER, NS_LITERAL_CSTRING("text/xml")); if (NS_FAILED(rv)) return rv; diff --git a/security/manager/ssl/src/TransportSecurityInfo.cpp b/security/manager/ssl/src/TransportSecurityInfo.cpp index cc9cfbfc9bb3..878435b0ef0a 100644 --- a/security/manager/ssl/src/TransportSecurityInfo.cpp +++ b/security/manager/ssl/src/TransportSecurityInfo.cpp @@ -289,8 +289,8 @@ TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result) // of the previous value. This is so when older versions attempt to // read a newer serialized TransportSecurityInfo, they will actually // fail and return NS_ERROR_FAILURE instead of silently failing. -#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0xf40a, 0x4060, \ - { 0xb2, 0xe1, 0x62, 0xab, 0x2b, 0x85, 0x26, 0xa9 } } +#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0xda1f, 0x4008, \ + { 0xac, 0x3c, 0x52, 0x86, 0x21, 0x54, 0x10, 0x70 } } static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC); NS_IMETHODIMP @@ -325,9 +325,15 @@ TransportSecurityInfo::Write(nsIObjectOutputStream* stream) if (NS_FAILED(rv)) { return rv; } + + // For successful connections and for connections with overridable errors, + // mSSLStatus will be non-null. However, for connections with non-overridable + // errors, it will be null. nsCOMPtr serializable(mSSLStatus); - rv = stream->WriteCompoundObject(serializable, NS_GET_IID(nsISSLStatus), - true); + rv = NS_WriteOptionalCompoundObject(stream, + serializable, + NS_GET_IID(nsISSLStatus), + true); if (NS_FAILED(rv)) { return rv; } @@ -385,16 +391,18 @@ TransportSecurityInfo::Read(nsIObjectInputStream* stream) if (NS_FAILED(rv)) { return rv; } + mErrorCode = 0; + + // For successful connections and for connections with overridable errors, + // mSSLStatus will be non-null. For connections with non-overridable errors, + // it will be null. nsCOMPtr supports; - rv = stream->ReadObject(true, getter_AddRefs(supports)); + rv = NS_ReadOptionalObject(stream, true, getter_AddRefs(supports)); if (NS_FAILED(rv)) { return rv; } mSSLStatus = reinterpret_cast(supports.get()); - if (!mSSLStatus) { - return NS_ERROR_FAILURE; - } nsCOMPtr failedCertChainSupports; rv = NS_ReadOptionalObject(stream, true, getter_AddRefs(failedCertChainSupports)); diff --git a/toolkit/components/places/nsAnnoProtocolHandler.cpp b/toolkit/components/places/nsAnnoProtocolHandler.cpp index 0ab98e175ba9..115eed6c5151 100644 --- a/toolkit/components/places/nsAnnoProtocolHandler.cpp +++ b/toolkit/components/places/nsAnnoProtocolHandler.cpp @@ -335,8 +335,12 @@ nsAnnoProtocolHandler::NewFaviconChannel(nsIURI *aURI, nsIURI *aAnnotationURI, // Create our channel. We'll call SetContentType with the right type when // we know what it actually is. nsCOMPtr channel; - rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, inputStream, - EmptyCString()); + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), + aURI, + inputStream, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_NORMAL, + nsIContentPolicy::TYPE_OTHER); NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel)); // Now we go ahead and get our data asynchronously for the favicon. diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 67e6cc689ef2..6704b96c2c18 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -2145,6 +2145,46 @@ "extended_statistics_ok": true, "description": "Time for a renewed DNS OS resolution (msec)" }, + "DNS_RENEWAL_TIME_FOR_TTL": { + "expires_in_version": "never", + "kind": "exponential", + "high": "60000", + "n_buckets": 50, + "extended_statistics_ok": true, + "description": "Time for a DNS OS resolution (msec) used to get TTL" + }, + "DNS_RENEWAL_TIME_FOR_TTL__TTL_ONLY_EXPT": { + "expires_in_version": "never", + "kind": "exponential", + "high": "60000", + "n_buckets": 50, + "extended_statistics_ok": true, + "description": "Time for a DNS OS resolution (msec) used to get TTL - TTL Only Experiment" + }, + "DNS_RENEWAL_TIME_FOR_TTL__TTL_PLUS_CONST_GRACE_EXPT": { + "expires_in_version": "never", + "kind": "exponential", + "high": "60000", + "n_buckets": 50, + "extended_statistics_ok": true, + "description": "Time for a DNS OS resolution (msec) used to get TTL - TTL + Const Grace Period Experiment" + }, + "DNS_RENEWAL_TIME__TTL_ONLY_EXPT": { + "expires_in_version": "never", + "kind": "exponential", + "high": "60000", + "n_buckets": 50, + "extended_statistics_ok": true, + "description": "Time for a renewed DNS OS resolution (msec) - TTL Only Experiment" + }, + "DNS_RENEWAL_TIME__TTL_PLUS_CONST_GRACE_EXPT": { + "expires_in_version": "never", + "kind": "exponential", + "high": "60000", + "n_buckets": 50, + "extended_statistics_ok": true, + "description": "Time for a renewed DNS OS resolution (msec) - TTL + Const Grace Period Experiment" + }, "DNS_FAILED_LOOKUP_TIME": { "expires_in_version": "never", "kind": "exponential", @@ -2569,6 +2609,42 @@ "kind": "flag", "description": "A plugin object was successfully invoked as a function" }, + "FLASH_PLUGIN_STATES": { + "expires_in_version": "50", + "kind": "enumerated", + "n_values": 20, + "description": "A flash object's initialization state" + }, + "FLASH_PLUGIN_AREA": { + "expires_in_version": "50", + "kind": "exponential", + "low": "256", + "high": "16777216", + "n_buckets": 50, + "description": "Flash object area (width * height)" + }, + "FLASH_PLUGIN_WIDTH": { + "expires_in_version": "50", + "kind": "linear", + "low": "1", + "high": "2000", + "n_buckets": 50, + "description": "Flash object width" + }, + "FLASH_PLUGIN_HEIGHT": { + "expires_in_version": "50", + "kind": "linear", + "low": "1", + "high": "2000", + "n_buckets": 50, + "description": "Flash object height" + }, + "FLASH_PLUGIN_INSTANCES_ON_PAGE": { + "expires_in_version": "50", + "kind": "enumerated", + "n_values": 30, + "description": "Flash object instances count on page" + }, "MOZ_SQLITE_OPEN_MS": { "expires_in_version": "default", "kind": "exponential", diff --git a/toolkit/themes/linux/global/jar.mn b/toolkit/themes/linux/global/jar.mn index 36d1f7535453..7e01edce4feb 100644 --- a/toolkit/themes/linux/global/jar.mn +++ b/toolkit/themes/linux/global/jar.mn @@ -67,3 +67,4 @@ toolkit.jar: skin/classic/global/in-content/sorter.png (../../shared/in-content/sorter.png) skin/classic/global/in-content/sorter@2x.png (../../shared/in-content/sorter@2x.png) + skin/classic/global/toolbar/spring.png (toolbar/spring.png) + skin/classic/global/spinner.png (../../shared/spinner.png) diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn index 02f70da4f060..03b25d1814c0 100644 --- a/toolkit/themes/osx/global/jar.mn +++ b/toolkit/themes/osx/global/jar.mn @@ -206,3 +206,4 @@ toolkit.jar: skin/classic/global/tree/columnpicker.gif (tree/columnpicker.gif) skin/classic/global/tree/folder.png (tree/folder.png) skin/classic/global/tree/folder@2x.png (tree/folder@2x.png) + skin/classic/global/spinner.png (../../shared/spinner.png) diff --git a/toolkit/themes/shared/spinner.png b/toolkit/themes/shared/spinner.png new file mode 100644 index 000000000000..82bac5325423 Binary files /dev/null and b/toolkit/themes/shared/spinner.png differ diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index 9494faf9851f..070f60f11fe9 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -201,6 +201,7 @@ toolkit.jar: skin/classic/global/tree/sort-dsc-classic.png (tree/sort-dsc-classic.png) skin/classic/global/tree/twisty-clsd.png (tree/twisty-clsd.png) skin/classic/global/tree/twisty-open.png (tree/twisty-open.png) + skin/classic/global/spinner.png (../../shared/spinner.png) #ifdef XP_WIN toolkit.jar: diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 4285bef727be..25e5d49b2bde 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -544,7 +544,6 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { AUDIO_OGG, "opus", "Opus Audio" }, #ifdef MOZ_WIDGET_GONK { AUDIO_AMR, "amr", "Adaptive Multi-Rate Audio" }, - { AUDIO_3GPP, "3gpp,3gp", "3GPP Audio" }, #endif { VIDEO_WEBM, "webm", "Web Media Video" }, { AUDIO_WEBM, "webm", "Web Media Audio" }, @@ -555,6 +554,12 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { AUDIO_WAV, "wav", "Waveform Audio" }, { VIDEO_3GPP, "3gpp,3gp", "3GPP Video" }, { VIDEO_3GPP2,"3g2", "3GPP2 Video" }, +#ifdef MOZ_WIDGET_GONK + // The AUDIO_3GPP has to come after the VIDEO_3GPP entry because the Gallery + // app on Firefox OS depends on the "3gp" extension mapping to the + // "video/3gpp" MIME type. + { AUDIO_3GPP, "3gpp,3gp", "3GPP Audio" }, +#endif { AUDIO_MIDI, "mid", "Standard MIDI Audio" } }; diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 58702163f806..75accb2524e6 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include "nsAppShell.h" #include "nsWindow.h" @@ -1029,7 +1028,7 @@ Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv* jenv, jclass) if (PR_IntervalNow() - startTime >= timeout) { return nullptr; } - sched_yield(); + usleep(100000ul); // Sleep for 100ms profile = ProfilePtr(profiler_get_profile()); }