diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 4998f85cbc38..3ba075cf886b 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -693,50 +693,57 @@ pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5); // Kernel parameters for process priorities. These affect how processes are // killed on low-memory and their relative CPU priorities. // -// Note: The maximum nice value on Linux is 19, but the max value you should -// use here is 18. NSPR adds 1 to some threads' nice values, to mark -// low-priority threads. If the process priority manager were to renice a -// process (and all its threads) to 19, all threads would have the same -// niceness. Then when we reniced the process to (say) 10, all threads would -// /still/ have the same niceness; we'd effectively have erased NSPR's thread -// priorities. - // The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is // okay, kernel will still kill processes with larger OomScoreAdjust first even // its OomScoreAdjust don't have a corresponding KillUnderKB. pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0); pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096); -pref("hal.processPriorityManager.gonk.MASTER.Nice", 0); +pref("hal.processPriorityManager.gonk.MASTER.cgroup", ""); pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67); -pref("hal.processPriorityManager.gonk.PREALLOC.Nice", 18); +pref("hal.processPriorityManager.gonk.PREALLOC.cgroup", "apps/bg_non_interactive"); pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67); pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120); -pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0); +pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.cgroup", "apps/critical"); pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134); pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144); -pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1); +pref("hal.processPriorityManager.gonk.FOREGROUND.cgroup", "apps"); pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200); -pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.Nice", 1); +pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.cgroup", "apps"); pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400); pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 7168); -pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 7); +pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.cgroup", "apps/bg_perceivable"); pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 534); pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderKB", 8192); -pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.Nice", 18); +pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.cgroup", "apps/bg_non_interactive"); pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667); pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480); -pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18); +pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive"); -// Processes get this niceness when they have low CPU priority. -pref("hal.processPriorityManager.gonk.LowCPUNice", 18); +// Control group definitions (i.e., CPU priority groups) for B2G processes. + +// Foreground apps +pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024); +pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 0); + +// Foreground apps with high priority, 16x more CPU than foreground ones +pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384); +pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 0); + +// Background perceivable apps, ~10x less CPU than foreground ones +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103); +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0); + +// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52); +pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0); // By default the compositor thread on gonk runs without real-time priority. RT // priority can be enabled by setting this pref to a value between 1 and 99. diff --git a/browser/base/content/pageinfo/permissions.js b/browser/base/content/pageinfo/permissions.js index ac35b94be887..55a67a99365b 100644 --- a/browser/base/content/pageinfo/permissions.js +++ b/browser/base/content/pageinfo/permissions.js @@ -266,7 +266,7 @@ function initPluginsRow() { let vulnerableLabel = document.getElementById("browserBundle").getString("pluginActivateVulnerable.label"); let pluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost); - let permissionMap = Map(); + let permissionMap = new Map(); for (let plugin of pluginHost.getPluginTags()) { if (plugin.disabled) { diff --git a/browser/devtools/framework/ToolboxProcess.jsm b/browser/devtools/framework/ToolboxProcess.jsm index 88eed9aa0b7f..482485f113b8 100644 --- a/browser/devtools/framework/ToolboxProcess.jsm +++ b/browser/devtools/framework/ToolboxProcess.jsm @@ -28,7 +28,7 @@ const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}) this.EXPORTED_SYMBOLS = ["BrowserToolboxProcess"]; -let processes = Set(); +let processes = new Set(); /** * Constructor for creating a process that will hold a chrome toolbox. diff --git a/browser/devtools/shared/widgets/VariablesView.jsm b/browser/devtools/shared/widgets/VariablesView.jsm index dd080571029c..7c21e945e4f2 100644 --- a/browser/devtools/shared/widgets/VariablesView.jsm +++ b/browser/devtools/shared/widgets/VariablesView.jsm @@ -2116,7 +2116,7 @@ Scope.prototype = { // Creating maps and arrays thousands of times for variables or properties // with a large number of children fills up a lot of memory. Make sure // these are instantiated only if needed. -DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_store", Map); +DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_store", () => new Map()); DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_enumItems", Array); DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_nonEnumItems", Array); diff --git a/browser/devtools/shared/widgets/ViewHelpers.jsm b/browser/devtools/shared/widgets/ViewHelpers.jsm index e4bda2784fda..aac494789be4 100644 --- a/browser/devtools/shared/widgets/ViewHelpers.jsm +++ b/browser/devtools/shared/widgets/ViewHelpers.jsm @@ -617,7 +617,7 @@ Item.prototype = { // Creating maps thousands of times for widgets with a large number of children // fills up a lot of memory. Make sure these are instantiated only if needed. -DevToolsUtils.defineLazyPrototypeGetter(Item.prototype, "_itemsByElement", Map); +DevToolsUtils.defineLazyPrototypeGetter(Item.prototype, "_itemsByElement", () => new Map()); /** * Some generic Widget methods handling Item instances. diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 168ac0006fc6..06c2ada3c136 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -318,43 +318,6 @@ FindObjectClass(JSContext* cx, JSObject* aGlobalObject) sObjectClass = js::GetObjectJSClass(obj); } -static inline nsresult -WrapNative(JSContext *cx, nsISupports *native, - nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle vp, - bool aAllowWrapping) -{ - if (!native) { - vp.setNull(); - - return NS_OK; - } - - JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp); - if (wrapper) { - return NS_OK; - } - - JS::Rooted scope(cx, JS::CurrentGlobalOrNull(cx)); - return nsDOMClassInfo::XPConnect()->WrapNativeToJSVal(cx, scope, native, - cache, aIID, - aAllowWrapping, vp); -} - -static inline nsresult -WrapNative(JSContext *cx, nsISupports *native, const nsIID* aIID, - bool aAllowWrapping, JS::MutableHandle vp) -{ - return WrapNative(cx, native, nullptr, aIID, vp, aAllowWrapping); -} - -// Same as the WrapNative above, but use these if aIID is nsISupports' IID. -static inline nsresult -WrapNative(JSContext *cx, nsISupports *native, - bool aAllowWrapping, JS::MutableHandle vp) -{ - return WrapNative(cx, native, nullptr, nullptr, vp, aAllowWrapping); -} - // Helper to handle torn-down inner windows. static inline nsresult SetParentToWindow(nsGlobalWindow *win, JSObject **parent) @@ -1349,7 +1312,7 @@ BaseStubConstructor(nsIWeakReference* aWeakOwner, } js::AssertSameCompartment(cx, obj); - return WrapNative(cx, native, true, args.rval()); + return nsContentUtils::WrapNative(cx, native, args.rval(), true); } static nsresult @@ -1792,7 +1755,7 @@ nsDOMConstructor::ToString(nsAString &aResult) static nsresult GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin, const nsGlobalNameStruct *aNameStruct, - nsIXPConnectJSObjectHolder **aProto) + JS::MutableHandle aProto) { NS_ASSERTION(aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor || @@ -1813,18 +1776,14 @@ GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin, } NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED); + nsCOMPtr proto_holder; nsresult rv = aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci, - aProto); + getter_AddRefs(proto_holder)); NS_ENSURE_SUCCESS(rv, rv); - JS::Rooted proto_obj(cx, (*aProto)->GetJSObject()); - if (!JS_WrapObject(cx, &proto_obj)) { - return NS_ERROR_FAILURE; - } - - NS_IF_RELEASE(*aProto); - return aXPConnect->HoldObject(cx, proto_obj, aProto); + aProto.set(proto_holder->GetJSObject()); + return JS_WrapObject(cx, aProto) ? NS_OK : NS_ERROR_FAILURE; } // Either ci_data must be non-null or name_struct must be non-null and of type @@ -1852,8 +1811,9 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, JS::Rooted v(cx); js::AssertSameCompartment(cx, obj); - rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), - false, &v); + rv = nsContentUtils::WrapNative(cx, constructor, + &NS_GET_IID(nsIDOMDOMConstructor), &v, + false); NS_ENSURE_SUCCESS(rv, rv); FillPropertyDescriptor(ctorDesc, obj, 0, v); @@ -2223,8 +2183,9 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, JS::Rooted v(cx); js::AssertSameCompartment(cx, obj); - rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), - false, &v); + rv = nsContentUtils::WrapNative(cx, constructor, + &NS_GET_IID(nsIDOMDOMConstructor), &v, + false); NS_ENSURE_SUCCESS(rv, rv); JS::Rooted class_obj(cx, &v.toObject()); @@ -2255,10 +2216,12 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, // Create the XPConnect prototype for our classinfo, PostCreateProto will // set up the prototype chain. This will go ahead and define things on the // actual window's global. - nsCOMPtr proto_holder; + JS::Rooted dot_prototype(cx); rv = GetXPCProto(nsDOMClassInfo::sXPConnect, cx, aWin, name_struct, - getter_AddRefs(proto_holder)); + &dot_prototype); NS_ENSURE_SUCCESS(rv, rv); + MOZ_ASSERT(dot_prototype); + bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj); MOZ_ASSERT_IF(obj != aWin->GetGlobalJSObject(), isXray); if (!isXray) { @@ -2269,9 +2232,6 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, // This is the Xray case. Look up the constructor object for this // prototype. - JS::Rooted dot_prototype(cx, proto_holder->GetJSObject()); - NS_ENSURE_STATE(dot_prototype); - const nsDOMClassInfoData *ci_data; if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { ci_data = &sClassInfoData[name_struct->mDOMClassInfoID]; @@ -2301,13 +2261,11 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, // We need to use the XPConnect prototype for the DOM class that this // constructor is an alias for (for example for Image we need the prototype // for HTMLImageElement). - nsCOMPtr proto_holder; + JS::Rooted dot_prototype(cx); rv = GetXPCProto(nsDOMClassInfo::sXPConnect, cx, aWin, alias_struct, - getter_AddRefs(proto_holder)); + &dot_prototype); NS_ENSURE_SUCCESS(rv, rv); - - JSObject* dot_prototype = proto_holder->GetJSObject(); - NS_ENSURE_STATE(dot_prototype); + MOZ_ASSERT(dot_prototype); const nsDOMClassInfoData *ci_data; if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { @@ -2332,8 +2290,9 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, JS::Rooted val(cx); js::AssertSameCompartment(cx, obj); - rv = WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), - true, &val); + rv = nsContentUtils::WrapNative(cx, constructor, + &NS_GET_IID(nsIDOMDOMConstructor), &val, + true); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(val.isObject(), "Why didn't we get a JSObject?"); @@ -2370,7 +2329,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, NS_ENSURE_TRUE(inner, NS_ERROR_UNEXPECTED); } - rv = WrapNative(cx, native, true, &prop_val); + rv = nsContentUtils::WrapNative(cx, native, &prop_val, true); } NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/interfaces/settings/nsISettingsService.idl b/dom/interfaces/settings/nsISettingsService.idl index a32fcd3842a3..b74da447f2ea 100644 --- a/dom/interfaces/settings/nsISettingsService.idl +++ b/dom/interfaces/settings/nsISettingsService.idl @@ -29,8 +29,9 @@ interface nsISettingsServiceLock : nsISupports void get(in string aName, in nsISettingsServiceCallback aCallback); }; -[scriptable, uuid(0505acf0-8e76-11e3-baa8-0800200c9a66)] +[scriptable, uuid(d1ed155c-9f90-47bb-91c2-7eac54d69f4b)] interface nsISettingsService : nsISupports { nsISettingsServiceLock createLock([optional] in nsISettingsTransactionCompleteCallback aCallback); + void receiveMessage(in jsval aMessage); }; diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 6c0f83482626..ba7a2ac275aa 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -201,15 +201,6 @@ IsAndroidAvailable() #ifndef MOZ_WIDGET_ANDROID return false; #else - // PowerVR is very slow at texture allocation for some reason, which causes poor performance. - nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); - - nsString vendor; - if (NS_FAILED(gfxInfo->GetAdapterVendorID(vendor)) || - vendor.Find("Imagination") == 0) { - return nullptr; - } - // We need android.media.MediaCodec which exists in API level 16 and higher. return AndroidBridge::Bridge()->GetAPIVersion() >= 16; #endif diff --git a/dom/media/fmp4/android/AndroidDecoderModule.cpp b/dom/media/fmp4/android/AndroidDecoderModule.cpp index f0cdebeb8344..84fbd4ef3f54 100644 --- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -70,26 +70,18 @@ public: return MediaCodecDataDecoder::Input(aSample); } - EGLImage CopySurface() { - if (!EnsureGLContext()) { - return nullptr; - } - - nsRefPtr img = mImageContainer->CreateImage(ImageFormat::SURFACE_TEXTURE); - layers::SurfaceTextureImage::Data data; - data.mSurfTex = mSurfaceTexture.get(); - data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height); - data.mOriginPos = gl::OriginPos::BottomLeft; - - layers::SurfaceTextureImage* stImg = static_cast(img.get()); - stImg->SetData(data); + bool WantCopy() { + // Allocating a texture is incredibly slow on PowerVR + return mGLContext->Vendor() != GLVendor::Imagination; + } + EGLImage CopySurface(layers::Image* img) { mGLContext->MakeCurrent(); - GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(), data.mSize); + GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(), img->GetSize()); GLBlitHelper helper(mGLContext); - if (!helper.BlitImageToTexture(img, data.mSize, tex, LOCAL_GL_TEXTURE_2D)) { + if (!helper.BlitImageToTexture(img, img->GetSize(), tex, LOCAL_GL_TEXTURE_2D)) { mGLContext->fDeleteTextures(1, &tex); return nullptr; } @@ -109,39 +101,53 @@ public: } virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, Microseconds aDuration) MOZ_OVERRIDE { - VideoInfo videoInfo; - videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height); - - EGLImage eglImage = CopySurface(); - if (!eglImage) { + if (!EnsureGLContext()) { return NS_ERROR_FAILURE; } - EGLSync eglSync = nullptr; - if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && - mGLContext->IsExtensionSupported(GLContext::OES_EGL_sync)) - { - MOZ_ASSERT(mGLContext->IsCurrent()); - eglSync = sEGLLibrary.fCreateSync(EGL_DISPLAY(), - LOCAL_EGL_SYNC_FENCE, - nullptr); - if (eglSync) { - mGLContext->fFlush(); - } - } else { - NS_WARNING("No EGL fence support detected, rendering artifacts may occur!"); - } + VideoInfo videoInfo; + videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height); - nsRefPtr img = mImageContainer->CreateImage(ImageFormat::EGLIMAGE); - layers::EGLImageImage::Data data; - data.mImage = eglImage; - data.mSync = eglSync; - data.mOwns = true; + nsRefPtr img = mImageContainer->CreateImage(ImageFormat::SURFACE_TEXTURE); + layers::SurfaceTextureImage::Data data; + data.mSurfTex = mSurfaceTexture.get(); data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height); data.mOriginPos = gl::OriginPos::BottomLeft; - layers::EGLImageImage* typedImg = static_cast(img.get()); - typedImg->SetData(data); + layers::SurfaceTextureImage* stImg = static_cast(img.get()); + stImg->SetData(data); + + if (WantCopy()) { + EGLImage eglImage = CopySurface(img); + if (!eglImage) { + return NS_ERROR_FAILURE; + } + + EGLSync eglSync = nullptr; + if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && + mGLContext->IsExtensionSupported(GLContext::OES_EGL_sync)) + { + MOZ_ASSERT(mGLContext->IsCurrent()); + eglSync = sEGLLibrary.fCreateSync(EGL_DISPLAY(), + LOCAL_EGL_SYNC_FENCE, + nullptr); + MOZ_ASSERT(eglSync); + mGLContext->fFlush(); + } else { + NS_WARNING("No EGL fence support detected, rendering artifacts may occur!"); + } + + img = mImageContainer->CreateImage(ImageFormat::EGLIMAGE); + layers::EGLImageImage::Data data; + data.mImage = eglImage; + data.mSync = eglSync; + data.mOwns = true; + data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height); + data.mOriginPos = gl::OriginPos::BottomLeft; + + layers::EGLImageImage* typedImg = static_cast(img.get()); + typedImg->SetData(data); + } nsresult rv; int32_t flags; diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 9ffe874ad495..bd75c9ef829e 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -32,8 +32,7 @@ extern PRLogModuleInfo* GetMediaSourceAPILog(); namespace mozilla { ContainerParser::ContainerParser() - : mInitData(new LargeDataBuffer()) - , mHasInitData(false) + : mHasInitData(false) { } @@ -81,10 +80,15 @@ ContainerParser::GetRoundingError() return 0; } +bool +ContainerParser::HasCompleteInitData() +{ + return mHasInitData && !!mInitData->Length(); +} + LargeDataBuffer* ContainerParser::InitData() { - MOZ_ASSERT(mHasInitData); return mInitData; } @@ -107,7 +111,9 @@ public: // ... // DocType == "webm" // ... - // 0x18538067 // Segment (must be "unknown" size) + // 0x18538067 // Segment (must be "unknown" size or contain a value large + // enough to include the Segment Information and Tracks + // elements that follow) // 0x1549a966 // -> Segment Info // 0x1654ae6b // -> One or more Tracks if (aData->Length() >= 4 && @@ -147,6 +153,8 @@ public: mOffset = 0; mParser = WebMBufferedParser(0); mOverlappedMapping.Clear(); + mInitData = new LargeDataBuffer(); + mResource = new SourceBufferResource(NS_LITERAL_CSTRING("video/webm")); } // XXX if it only adds new mappings, overlapped but not available @@ -156,22 +164,27 @@ public: mOverlappedMapping.Clear(); ReentrantMonitor dummy("dummy"); mParser.Append(aData->Elements(), aData->Length(), mapping, dummy); + if (mResource) { + mResource->AppendData(aData); + } // XXX This is a bit of a hack. Assume if there are no timecodes // present and it's an init segment that it's _just_ an init segment. // We should be more precise. - if (initSegment) { - uint32_t length = aData->Length(); - if (!mapping.IsEmpty()) { - length = mapping[0].mSyncOffset; - MOZ_ASSERT(length <= aData->Length()); - } - MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.", - this, length); - if (!mInitData->ReplaceElementsAt(0, mInitData->Length(), - aData->Elements(), length)) { - // Unlikely OOM - return false; + if (initSegment || !HasCompleteInitData()) { + if (mParser.mInitEndOffset > 0) { + MOZ_ASSERT(mParser.mInitEndOffset <= mResource->GetLength()); + if (!mInitData->SetLength(mParser.mInitEndOffset)) { + // Super unlikely OOM + return false; + } + char* buffer = reinterpret_cast(mInitData->Elements()); + mResource->ReadFromCache(buffer, 0, mParser.mInitEndOffset); + MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.", + this, mParser.mInitEndOffset); + mResource = nullptr; + } else { + MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: Incomplete init found."); } mHasInitData = true; } @@ -273,6 +286,7 @@ public: // manually. This allows the ContainerParser to be shared across different // timestampOffsets. mParser = new mp4_demuxer::MoofParser(mStream, 0, 0, &mMonitor); + mInitData = new LargeDataBuffer(); } else if (!mStream || !mParser) { return false; } @@ -284,16 +298,20 @@ public: byteRanges.AppendElement(mbr); mParser->RebuildFragmentedIndex(byteRanges); - if (initSegment) { + if (initSegment || !HasCompleteInitData()) { const MediaByteRange& range = mParser->mInitRange; - MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.", - this, range.mEnd - range.mStart); - - if (!mInitData->ReplaceElementsAt(0, mInitData->Length(), - aData->Elements() + range.mStart, - range.mEnd - range.mStart)) { - // Super unlikely OOM - return false; + uint32_t length = range.mEnd - range.mStart; + if (length) { + if (!mInitData->SetLength(length)) { + // Super unlikely OOM + return false; + } + char* buffer = reinterpret_cast(mInitData->Elements()); + mResource->ReadFromCache(buffer, range.mStart, length); + MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.", + this, length); + } else { + MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: Incomplete init found."); } mHasInitData = true; } @@ -322,7 +340,6 @@ public: private: nsRefPtr mStream; nsAutoPtr mParser; - nsRefPtr mResource; Monitor mMonitor; }; #endif diff --git a/dom/media/mediasource/ContainerParser.h b/dom/media/mediasource/ContainerParser.h index ee1337990949..872431eb6c13 100644 --- a/dom/media/mediasource/ContainerParser.h +++ b/dom/media/mediasource/ContainerParser.h @@ -12,6 +12,7 @@ namespace mozilla { class LargeDataBuffer; +class SourceBufferResource; class ContainerParser { public: @@ -48,10 +49,13 @@ public: return mHasInitData; } + bool HasCompleteInitData(); + static ContainerParser* CreateForMIMEType(const nsACString& aType); protected: nsRefPtr mInitData; + nsRefPtr mResource; bool mHasInitData; }; diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index 1021e09427f1..94087555b5ce 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -248,13 +248,11 @@ MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv) aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); return; } - if (sourceBuffer->Updating()) { - // TODO: - // abort stream append loop (if running) - // set updating to false - // fire "abort" at sourceBuffer - // fire "updateend" at sourceBuffer - } + + sourceBuffer->AbortBufferAppend(); + // TODO: + // abort stream append loop (if running) + // TODO: // For all sourceBuffer audioTracks, videoTracks, textTracks: // set sourceBuffer to null diff --git a/dom/media/mediasource/MediaSourceDecoder.cpp b/dom/media/mediasource/MediaSourceDecoder.cpp index db788873dd20..56d5c9518332 100644 --- a/dom/media/mediasource/MediaSourceDecoder.cpp +++ b/dom/media/mediasource/MediaSourceDecoder.cpp @@ -205,7 +205,7 @@ MediaSourceDecoder::DurationChanged(double aOldDuration, double aNewDuration) } void -MediaSourceDecoder::SetDecodedDuration(int64_t aDuration) +MediaSourceDecoder::SetInitialDuration(int64_t aDuration) { // Only use the decoded duration if one wasn't already // set. @@ -218,7 +218,7 @@ MediaSourceDecoder::SetDecodedDuration(int64_t aDuration) if (aDuration >= 0) { duration /= USECS_PER_S; } - DoSetMediaSourceDuration(duration); + SetMediaSourceDuration(duration, MSRangeRemovalAction::SKIP); } void @@ -226,13 +226,6 @@ MediaSourceDecoder::SetMediaSourceDuration(double aDuration, MSRangeRemovalActio { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); double oldDuration = mMediaSourceDuration; - DoSetMediaSourceDuration(aDuration); - ScheduleDurationChange(oldDuration, aDuration, aAction); -} - -void -MediaSourceDecoder::DoSetMediaSourceDuration(double aDuration) -{ if (aDuration >= 0) { mDecoderStateMachine->SetDuration(aDuration * USECS_PER_S); mMediaSourceDuration = aDuration; @@ -243,6 +236,7 @@ MediaSourceDecoder::DoSetMediaSourceDuration(double aDuration) if (mReader) { mReader->SetMediaSourceDuration(mMediaSourceDuration); } + ScheduleDurationChange(oldDuration, aDuration, aAction); } void diff --git a/dom/media/mediasource/MediaSourceDecoder.h b/dom/media/mediasource/MediaSourceDecoder.h index 2800e7de7ed1..968a31f1cb82 100644 --- a/dom/media/mediasource/MediaSourceDecoder.h +++ b/dom/media/mediasource/MediaSourceDecoder.h @@ -56,7 +56,7 @@ public: void Ended(); bool IsExpectingMoreData() MOZ_OVERRIDE; - void SetDecodedDuration(int64_t aDuration); + void SetInitialDuration(int64_t aDuration); void SetMediaSourceDuration(double aDuration, MSRangeRemovalAction aAction); double GetMediaSourceDuration(); void DurationChanged(double aOldDuration, double aNewDuration); diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index f5285788e40e..8fae73e89967 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -897,8 +897,6 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) return NS_ERROR_FAILURE; } - int64_t maxDuration = -1; - if (mAudioTrack) { MOZ_ASSERT(mAudioTrack->IsReady()); mAudioReader = mAudioTrack->Decoders()[0]->GetReader(); @@ -907,9 +905,9 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_ASSERT(info.HasAudio()); mInfo.mAudio = info.mAudio; mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted; - maxDuration = std::max(maxDuration, mAudioReader->GetDecoder()->GetMediaDuration()); - MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p maxDuration=%lld", - this, mAudioReader.get(), maxDuration); + MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p duration=%lld", + this, mAudioReader.get(), + mAudioReader->GetDecoder()->GetMediaDuration()); } if (mVideoTrack) { @@ -920,17 +918,11 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_ASSERT(info.HasVideo()); mInfo.mVideo = info.mVideo; mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted; - maxDuration = std::max(maxDuration, mVideoReader->GetDecoder()->GetMediaDuration()); - MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p maxDuration=%lld", - this, mVideoReader.get(), maxDuration); + MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p duration=%lld", + this, mVideoReader.get(), + mVideoReader->GetDecoder()->GetMediaDuration()); } - if (!maxDuration) { - // Treat a duration of 0 as infinity - maxDuration = -1; - } - static_cast(mDecoder)->SetDecodedDuration(maxDuration); - *aInfo = mInfo; *aTags = nullptr; // TODO: Handle metadata. diff --git a/dom/media/mediasource/SourceBuffer.cpp b/dom/media/mediasource/SourceBuffer.cpp index d4711f778817..f87099b1fe18 100644 --- a/dom/media/mediasource/SourceBuffer.cpp +++ b/dom/media/mediasource/SourceBuffer.cpp @@ -46,16 +46,18 @@ class AppendDataRunnable : public nsRunnable { public: AppendDataRunnable(SourceBuffer* aSourceBuffer, LargeDataBuffer* aData, - double aTimestampOffset) + double aTimestampOffset, + uint32_t aUpdateID) : mSourceBuffer(aSourceBuffer) , mData(aData) , mTimestampOffset(aTimestampOffset) + , mUpdateID(aUpdateID) { } NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL { - mSourceBuffer->AppendData(mData, mTimestampOffset); + mSourceBuffer->AppendData(mData, mTimestampOffset, mUpdateID); return NS_OK; } @@ -64,6 +66,7 @@ private: nsRefPtr mSourceBuffer; nsRefPtr mData; double mTimestampOffset; + uint32_t mUpdateID; }; class RangeRemovalRunnable : public nsRunnable { @@ -214,20 +217,23 @@ SourceBuffer::Abort(ErrorResult& aRv) aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } - Abort(); + AbortBufferAppend(); mTrackBuffer->ResetParserState(); mAppendWindowStart = 0; mAppendWindowEnd = PositiveInfinity(); - + // Discard the current decoder so no new data will be added to it. MSE_DEBUG("SourceBuffer(%p)::Abort() Discarding decoder", this); - mTrackBuffer->DiscardDecoder(); + mTrackBuffer->DiscardCurrentDecoder(); } void -SourceBuffer::Abort() +SourceBuffer::AbortBufferAppend() { if (mUpdating) { - // TODO: Abort segment parser loop, buffer append, and stream append loop algorithms. + mPendingAppend.DisconnectIfExists(); + // TODO: Abort segment parser loop, and stream append loop algorithms. + // cancel any pending buffer append. + mTrackBuffer->AbortAppendData(); AbortUpdating(); } } @@ -269,6 +275,8 @@ SourceBuffer::RangeRemoval(double aStart, double aEnd) void SourceBuffer::DoRangeRemoval(double aStart, double aEnd) { + MSE_DEBUG("SourceBuffer(%p)::DoRangeRemoval (updating:%d)", + this, mUpdating); if (!mUpdating) { // abort was called in between. return; @@ -287,7 +295,7 @@ SourceBuffer::Detach() { MOZ_ASSERT(NS_IsMainThread()); MSE_DEBUG("SourceBuffer(%p)::Detach", this); - Abort(); + AbortBufferAppend(); if (mTrackBuffer) { mTrackBuffer->Detach(); } @@ -312,6 +320,7 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType) , mTimestampOffset(0) , mAppendMode(SourceBufferAppendMode::Segments) , mUpdating(false) + , mUpdateID(0) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aMediaSource); @@ -363,6 +372,7 @@ SourceBuffer::StartUpdating() MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mUpdating); mUpdating = true; + mUpdateID++; QueueAsyncSimpleEvent("updatestart"); } @@ -397,9 +407,11 @@ SourceBuffer::AbortUpdating() void SourceBuffer::CheckEndTime() { + MOZ_ASSERT(NS_IsMainThread()); // Check if we need to update mMediaSource duration double endTime = GetBufferedEnd(); - if (endTime > mMediaSource->Duration()) { + double duration = mMediaSource->Duration(); + if (endTime > duration) { mMediaSource->SetDuration(endTime, MSRangeRemovalAction::SKIP); } } @@ -418,14 +430,15 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments, "We don't handle timestampOffset for sequence mode yet"); nsRefPtr task = - new AppendDataRunnable(this, data, mTimestampOffset); + new AppendDataRunnable(this, data, mTimestampOffset, mUpdateID); NS_DispatchToMainThread(task); } void -SourceBuffer::AppendData(LargeDataBuffer* aData, double aTimestampOffset) +SourceBuffer::AppendData(LargeDataBuffer* aData, double aTimestampOffset, + uint32_t aUpdateID) { - if (!mUpdating) { + if (!mUpdating || aUpdateID != mUpdateID) { // The buffer append algorithm has been interrupted by abort(). // // If the sequence appendBuffer(), abort(), appendBuffer() occurs before @@ -436,22 +449,53 @@ SourceBuffer::AppendData(LargeDataBuffer* aData, double aTimestampOffset) } MOZ_ASSERT(mMediaSource); + MOZ_ASSERT(!mPendingAppend.Exists()); - if (aData->Length()) { - if (!mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S)) { - AppendError(true); - return; - } + if (!aData->Length()) { + StopUpdating(); + return; + } - if (mTrackBuffer->HasInitSegment()) { - mMediaSource->QueueInitializationEvent(); - } + mPendingAppend.Begin(mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S) + ->RefableThen(NS_GetCurrentThread(), __func__, this, + &SourceBuffer::AppendDataCompletedWithSuccess, + &SourceBuffer::AppendDataErrored)); +} +void +SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia) +{ + mPendingAppend.Complete(); + if (!mUpdating) { + // The buffer append algorithm has been interrupted by abort(). + return; + } + + if (mTrackBuffer->HasInitSegment()) { + mMediaSource->QueueInitializationEvent(); + } + + if (aGotMedia) { CheckEndTime(); } StopUpdating(); - } +} + +void +SourceBuffer::AppendDataErrored(nsresult aError) +{ + mPendingAppend.Complete(); + switch (aError) { + case NS_ERROR_ABORT: + // Nothing further to do as the trackbuffer has been shutdown. + // or append was aborted and abort() has handled all the events. + break; + default: + AppendError(true); + break; + } +} void SourceBuffer::AppendError(bool aDecoderError) diff --git a/dom/media/mediasource/SourceBuffer.h b/dom/media/mediasource/SourceBuffer.h index 1f633a0c71ec..f0c5e4eec469 100644 --- a/dom/media/mediasource/SourceBuffer.h +++ b/dom/media/mediasource/SourceBuffer.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_SourceBuffer_h_ #define mozilla_dom_SourceBuffer_h_ +#include "MediaPromise.h" #include "MediaSource.h" #include "js/RootingAPI.h" #include "mozilla/Assertions.h" @@ -32,6 +33,7 @@ class ErrorResult; class LargeDataBuffer; class TrackBuffer; template class AsyncEventRunner; +typedef MediaPromise TrackBufferAppendPromise; namespace dom { @@ -80,7 +82,7 @@ public: void AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv); void Abort(ErrorResult& aRv); - void Abort(); + void AbortBufferAppend(); void Remove(double aStart, double aEnd, ErrorResult& aRv); /** End WebIDL Methods. */ @@ -139,7 +141,8 @@ private: // Shared implementation of AppendBuffer overloads. void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv); - void AppendData(LargeDataBuffer* aData, double aTimestampOffset); + void AppendData(LargeDataBuffer* aData, double aTimestampOffset, + uint32_t aAppendID); // Implement the "Append Error Algorithm". // Will call endOfStream() with "decode" error if aDecodeError is true. @@ -153,6 +156,9 @@ private: uint32_t aLength, ErrorResult& aRv); + void AppendDataCompletedWithSuccess(bool aValue); + void AppendDataErrored(nsresult aError); + nsRefPtr mMediaSource; uint32_t mEvictionThreshold; @@ -166,6 +172,13 @@ private: SourceBufferAppendMode mAppendMode; bool mUpdating; + + // Each time mUpdating is set to true, mUpdateID will be incremented. + // This allows for a queued AppendData task to identify if it was earlier + // aborted and another AppendData queued. + uint32_t mUpdateID; + + MediaPromiseConsumerHolder mPendingAppend; }; } // namespace dom diff --git a/dom/media/mediasource/SourceBufferResource.h b/dom/media/mediasource/SourceBufferResource.h index 00fa49bd882f..4888bb7ad00e 100644 --- a/dom/media/mediasource/SourceBufferResource.h +++ b/dom/media/mediasource/SourceBufferResource.h @@ -114,6 +114,11 @@ public: // Used by SourceBuffer. void AppendData(LargeDataBuffer* aData); void Ended(); + bool IsEnded() + { + ReentrantMonitorAutoEnter mon(mMonitor); + return mEnded; + } // Remove data from resource if it holds more than the threshold // number of bytes. Returns amount evicted. uint32_t EvictData(uint64_t aPlaybackOffset, uint32_t aThreshold); diff --git a/dom/media/mediasource/TrackBuffer.cpp b/dom/media/mediasource/TrackBuffer.cpp index 18e2f61d8edf..ff716803edfd 100644 --- a/dom/media/mediasource/TrackBuffer.cpp +++ b/dom/media/mediasource/TrackBuffer.cpp @@ -102,9 +102,19 @@ public: return true; } + size_t Length() + { + return mDecoders.Length(); + } + + void AppendElement(SourceBufferDecoder* aDecoder) + { + mDecoders.AppendElement(aDecoder); + } + private: TrackBuffer* mOwner; - nsAutoTArray,2> mDecoders; + nsAutoTArray,1> mDecoders; }; nsRefPtr @@ -112,6 +122,7 @@ TrackBuffer::Shutdown() { mParentDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); mShutdown = true; + mInitializationPromise.RejectIfExists(NS_ERROR_ABORT, __func__); MOZ_ASSERT(mShutdownPromise.IsEmpty()); nsRefPtr p = mShutdownPromise.Ensure(__func__); @@ -138,48 +149,84 @@ TrackBuffer::ContinueShutdown() return; } + mCurrentDecoder = nullptr; mInitializedDecoders.Clear(); mParentDecoder = nullptr; mShutdownPromise.Resolve(true, __func__); } -bool +nsRefPtr TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mInitializationPromise.IsEmpty()); + DecodersToInitialize decoders(this); + nsRefPtr p = mInitializationPromise.Ensure(__func__); + bool hadInitData = mParser->HasInitData(); + bool hadCompleteInitData = mParser->HasCompleteInitData(); + nsRefPtr oldInit = mParser->InitData(); + bool newInitData = mParser->IsInitSegmentPresent(aData); + // TODO: Run more of the buffer append algorithm asynchronously. - if (mParser->IsInitSegmentPresent(aData)) { + if (newInitData) { MSE_DEBUG("TrackBuffer(%p)::AppendData: New initialization segment.", this); - if (!decoders.NewDecoder(aTimestampOffset)) { - return false; - } - } else if (!mParser->HasInitData()) { + } else if (!hadInitData) { MSE_DEBUG("TrackBuffer(%p)::AppendData: Non-init segment appended during initialization.", this); - return false; + mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__); + return p; } - int64_t start, end; - if (mParser->ParseStartAndEndTimestamps(aData, start, end)) { + int64_t start = 0, end = 0; + bool gotMedia = mParser->ParseStartAndEndTimestamps(aData, start, end); + bool gotInit = mParser->HasCompleteInitData(); + + if (newInitData) { + if (!gotInit) { + // We need a new decoder, but we can't initialize it yet. + nsRefPtr decoder = NewDecoder(aTimestampOffset); + // The new decoder is stored in mDecoders/mCurrentDecoder, so we + // don't need to do anything with 'decoder'. It's only a placeholder. + if (!decoder) { + mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__); + return p; + } + } else { + if (!decoders.NewDecoder(aTimestampOffset)) { + mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__); + return p; + } + } + } else if (!hadCompleteInitData && gotInit) { + MOZ_ASSERT(mCurrentDecoder); + // Queue pending decoder for initialization now that we have a full + // init segment. + decoders.AppendElement(mCurrentDecoder); + } + + if (gotMedia) { start += aTimestampOffset; end += aTimestampOffset; - if (mParser->IsMediaSegmentPresent(aData) && - mLastEndTimestamp && + if (mLastEndTimestamp && (!mParser->TimestampsFuzzyEqual(start, mLastEndTimestamp.value()) || mLastTimestampOffset != aTimestampOffset || - mDecoderPerSegment || (mCurrentDecoder && mCurrentDecoder->WasTrimmed()))) { + mDecoderPerSegment || + (mCurrentDecoder && mCurrentDecoder->WasTrimmed()))) { MSE_DEBUG("TrackBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]", this, mLastStartTimestamp, mLastEndTimestamp.value(), start, end); - // This data is earlier in the timeline than data we have already - // processed, so we must create a new decoder to handle the decoding. - if (!decoders.NewDecoder(aTimestampOffset)) { - return false; + if (!newInitData) { + // This data is earlier in the timeline than data we have already + // processed or not continuous, so we must create a new decoder + // to handle the decoding. + if (!hadCompleteInitData || !decoders.NewDecoder(aTimestampOffset)) { + mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__); + return p; + } + MSE_DEBUG("TrackBuffer(%p)::AppendData: Decoder marked as initialized.", this); + AppendDataToCurrentResource(oldInit, 0); } - MSE_DEBUG("TrackBuffer(%p)::AppendData: Decoder marked as initialized.", this); - nsRefPtr initData = mParser->InitData(); - AppendDataToCurrentResource(initData, end - start); mLastStartTimestamp = start; } else { MSE_DEBUG("TrackBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]", @@ -190,13 +237,21 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset) } if (!AppendDataToCurrentResource(aData, end - start)) { - return false; + mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__); + return p; } - // Tell our reader that we have more data to ensure that playback starts if - // required when data is appended. - mParentDecoder->GetReader()->MaybeNotifyHaveData(); - return true; + if (decoders.Length()) { + // We're going to have to wait for the decoder to initialize, the promise + // will be resolved once initialization completes. + return p; + } else if (gotMedia) { + // Tell our reader that we have more data to ensure that playback starts if + // required when data is appended. + mParentDecoder->GetReader()->MaybeNotifyHaveData(); + } + mInitializationPromise.Resolve(gotMedia, __func__); + return p; } bool @@ -370,9 +425,9 @@ TrackBuffer::Buffered(dom::TimeRanges* aRanges) double highestEndTime = 0; - for (uint32_t i = 0; i < mDecoders.Length(); ++i) { + for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) { nsRefPtr r = new dom::TimeRanges(); - mDecoders[i]->GetBuffered(r); + mInitializedDecoders[i]->GetBuffered(r); if (r->Length() > 0) { highestEndTime = std::max(highestEndTime, r->GetEndTime()); aRanges->Union(r, double(mParser->GetRoundingError()) / USECS_PER_S); @@ -388,7 +443,7 @@ TrackBuffer::NewDecoder(int64_t aTimestampOffset) MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mParentDecoder); - DiscardDecoder(); + DiscardCurrentDecoder(); nsRefPtr decoder = mParentDecoder->CreateSubDecoder(mType, aTimestampOffset); if (!decoder) { @@ -410,6 +465,7 @@ bool TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder) { if (NS_WARN_IF(!mTaskQueue)) { + mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); return false; } @@ -418,8 +474,9 @@ TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder) &TrackBuffer::InitializeDecoder, aDecoder); if (NS_FAILED(mTaskQueue->Dispatch(task))) { - MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this); + MSE_DEBUG("TrackBuffer(%p): Failed to enqueue decoder initialization task", this); RemoveDecoder(aDecoder); + mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); return false; } return true; @@ -428,6 +485,11 @@ TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder) void TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder) { + if (!mParentDecoder) { + MSE_DEBUG("TrackBuffer(%p) was shutdown. Aborting initialization.", + this); + return; + } // ReadMetadata may block the thread waiting on data, so we must be able // to leave the monitor while we call it. For the rest of this function // we want to hold the monitor though, since we run on a different task queue @@ -435,12 +497,21 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder) mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn(); ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); + if (mCurrentDecoder != aDecoder) { + MSE_DEBUG("TrackBuffer(%p) append was cancelled. Aborting initialization.", + this); + // If we reached this point, the SourceBuffer would have disconnected + // the promise. So no need to reject it. + return; + } + // We may be shut down at any time by the reader on another thread. So we need // to check for this each time we acquire the monitor. If that happens, we // need to abort immediately, because the reader has forgotten about us, and // important pieces of our state (like mTaskQueue) have also been torn down. if (mShutdown) { MSE_DEBUG("TrackBuffer(%p) was shut down. Aborting initialization.", this); + RemoveDecoder(aDecoder); return; } @@ -452,10 +523,28 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder) MediaInfo mi; nsAutoPtr tags; // TODO: Handle metadata. nsresult rv; + + // HACK WARNING: + // We only reach this point once we know that we have a complete init segment. + // We don't want the demuxer to do a blocking read as no more data can be + // appended while this routine is running. Marking the SourceBufferResource + // as ended will cause any incomplete reads to abort. + // As this decoder hasn't been initialized yet, the resource isn't yet in use + // and so it is safe to do so. + bool wasEnded = aDecoder->GetResource()->IsEnded(); + if (!wasEnded) { + aDecoder->GetResource()->Ended(); + } { ReentrantMonitorAutoExit mon(mParentDecoder->GetReentrantMonitor()); rv = reader->ReadMetadata(&mi, getter_Transfers(tags)); } + if (!wasEnded) { + // Adding an empty buffer will reopen the SourceBufferResource + nsRefPtr emptyBuffer = new LargeDataBuffer; + aDecoder->GetResource()->AppendData(emptyBuffer); + } + // HACK END. reader->SetIdle(); if (mShutdown) { @@ -475,6 +564,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder) MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d", this, reader, rv, mi.HasAudio(), mi.HasVideo()); RemoveDecoder(aDecoder); + mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); return; } @@ -487,18 +577,63 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder) this, reader, mi.mAudio.mRate, mi.mAudio.mChannels); } - if (!RegisterDecoder(aDecoder)) { - // XXX: Need to signal error back to owning SourceBuffer. - MSE_DEBUG("TrackBuffer(%p): Reader %p not activated", this, reader); + RefPtr task = + NS_NewRunnableMethodWithArg(this, + &TrackBuffer::CompleteInitializeDecoder, + aDecoder); + if (NS_FAILED(NS_DispatchToMainThread(task))) { + MSE_DEBUG("TrackBuffer(%p): Failed to enqueue decoder initialization task", this); + RemoveDecoder(aDecoder); + mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); + return; + } +} + +void +TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder) +{ + if (!mParentDecoder) { + MSE_DEBUG("TrackBuffer(%p) was shutdown. Aborting initialization.", + this); + return; + } + ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); + if (mCurrentDecoder != aDecoder) { + MSE_DEBUG("TrackBuffer(%p) append was cancelled. Aborting initialization.", + this); + // If we reached this point, the SourceBuffer would have disconnected + // the promise. So no need to reject it. + return; + } + + if (mShutdown) { + MSE_DEBUG("TrackBuffer(%p) was shut down. Aborting initialization.", this); RemoveDecoder(aDecoder); return; } + if (!RegisterDecoder(aDecoder)) { + MSE_DEBUG("TrackBuffer(%p): Reader %p not activated", + this, aDecoder->GetReader()); + RemoveDecoder(aDecoder); + mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); + return; + } + + int64_t duration = aDecoder->GetMediaDuration(); + if (!duration) { + // Treat a duration of 0 as infinity + duration = -1; + } + mParentDecoder->SetInitialDuration(duration); + // Tell our reader that we have more data to ensure that playback starts if // required when data is appended. mParentDecoder->GetReader()->MaybeNotifyHaveData(); - MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader); + MSE_DEBUG("TrackBuffer(%p): Reader %p activated", + this, aDecoder->GetReader()); + mInitializationPromise.ResolveIfExists(aDecoder->GetRealMediaDuration() > 0, __func__); } bool @@ -541,12 +676,10 @@ TrackBuffer::RegisterDecoder(SourceBufferDecoder* aDecoder) } void -TrackBuffer::DiscardDecoder() +TrackBuffer::DiscardCurrentDecoder() { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - if (mCurrentDecoder) { - mCurrentDecoder->GetResource()->Ended(); - } + EndCurrentDecoder(); mCurrentDecoder = nullptr; } @@ -564,7 +697,7 @@ TrackBuffer::Detach() { MOZ_ASSERT(NS_IsMainThread()); if (mCurrentDecoder) { - DiscardDecoder(); + DiscardCurrentDecoder(); } } @@ -572,7 +705,7 @@ bool TrackBuffer::HasInitSegment() { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - return mParser->HasInitData(); + return mParser->HasCompleteInitData(); } bool @@ -580,7 +713,7 @@ TrackBuffer::IsReady() { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); MOZ_ASSERT((mInfo.HasAudio() || mInfo.HasVideo()) || mInitializedDecoders.IsEmpty()); - return mParser->HasInitData() && (mInfo.HasAudio() || mInfo.HasVideo()); + return mInfo.HasAudio() || mInfo.HasVideo(); } bool @@ -626,7 +759,24 @@ TrackBuffer::ResetDecode() void TrackBuffer::ResetParserState() { - // TODO + MOZ_ASSERT(NS_IsMainThread()); + + if (mParser->HasInitData() && !mParser->HasCompleteInitData()) { + // We have an incomplete init segment pending. reset current parser and + // discard the current decoder. + mParser = ContainerParser::CreateForMIMEType(mType); + DiscardCurrentDecoder(); + } +} + +void +TrackBuffer::AbortAppendData() +{ + DiscardCurrentDecoder(); + // The SourceBuffer would have disconnected its promise. + // However we must ensure that the MediaPromiseHolder handle all pending + // promises. + mInitializationPromise.RejectIfExists(NS_ERROR_ABORT, __func__); } const nsTArray>& @@ -717,7 +867,7 @@ TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder) mDecoders.RemoveElement(aDecoder); if (mCurrentDecoder == aDecoder) { - DiscardDecoder(); + DiscardCurrentDecoder(); } } aDecoder->GetReader()->GetTaskQueue()->Dispatch(task); diff --git a/dom/media/mediasource/TrackBuffer.h b/dom/media/mediasource/TrackBuffer.h index 841e4c66e821..670fe629f33d 100644 --- a/dom/media/mediasource/TrackBuffer.h +++ b/dom/media/mediasource/TrackBuffer.h @@ -7,8 +7,8 @@ #ifndef MOZILLA_TRACKBUFFER_H_ #define MOZILLA_TRACKBUFFER_H_ +#include "SourceBuffer.h" #include "SourceBufferDecoder.h" -#include "MediaPromise.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/mozalloc.h" @@ -40,7 +40,8 @@ public: // Append data to the current decoder. Also responsible for calling // NotifyDataArrived on the decoder to keep buffered range computation up // to date. Returns false if the append failed. - bool AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset /* microseconds */); + nsRefPtr AppendData(LargeDataBuffer* aData, + int64_t aTimestampOffset /* microseconds */); // Evicts data held in the current decoders SourceBufferResource from the // start of the buffer through to aPlaybackTime. aThreshold is used to @@ -61,7 +62,7 @@ public: // Mark the current decoder's resource as ended, clear mCurrentDecoder and // reset mLast{Start,End}Timestamp. - void DiscardDecoder(); + void DiscardCurrentDecoder(); // Mark the current decoder's resource as ended. void EndCurrentDecoder(); @@ -100,6 +101,9 @@ public: // Times are in microseconds. bool RangeRemoval(int64_t aStart, int64_t aEnd); + // Abort any pending appendBuffer by rejecting any pending promises. + void AbortAppendData(); + #ifdef MOZ_EME nsresult SetCDMProxy(CDMProxy* aProxy); #endif @@ -130,6 +134,11 @@ private: // Runs decoder initialization including calling ReadMetadata. Runs as an // event on the decode thread pool. void InitializeDecoder(SourceBufferDecoder* aDecoder); + // Once decoder has been initialized, set mediasource duration if required + // and resolve any pending InitializationPromise. + // Setting the mediasource duration must be done on the main thread. + // TODO: Why is that so? + void CompleteInitializeDecoder(SourceBufferDecoder* aDecoder); // Adds a successfully initialized decoder to mDecoders and (if it's the // first decoder initialized), initializes mHasAudio/mHasVideo. Called @@ -193,6 +202,9 @@ private: MediaPromiseHolder mShutdownPromise; bool mDecoderPerSegment; bool mShutdown; + + MediaPromiseHolder mInitializationPromise; + }; } // namespace mozilla diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index 9e5d87c5a894..6b4d59af5039 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -455,6 +455,7 @@ skip-if = appname == "seamonkey" [test_playback.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_playback_errors.html] +skip-if = toolkit == 'gonk' # bug 1128845 [test_playback_rate.html] skip-if = (toolkit == 'android' && processor == 'x86') #bug 845162 [test_playback_rate_playpause.html] @@ -467,7 +468,7 @@ skip-if = true # bug 493692 [test_progress.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_reactivate.html] -skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 +skip-if = toolkit == 'gonk' || (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 and bug 1128845 on gonk [test_readyState.html] [test_referer.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only @@ -525,7 +526,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_trackelementevent.html] [test_trackevent.html] [test_unseekable.html] -skip-if = (toolkit == 'android' && processor == 'x86') #x86 only +skip-if = toolkit == 'gonk' || (toolkit == 'android' && processor == 'x86') #x86 only and bug 1128845 on gonk [test_video_to_canvas.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_video_in_audio_element.html] diff --git a/dom/media/test/test_bug686942.html b/dom/media/test/test_bug686942.html index 2ecd26be0118..2f67dfa6e9ad 100644 --- a/dom/media/test/test_bug686942.html +++ b/dom/media/test/test_bug686942.html @@ -23,6 +23,7 @@ var manager = new MediaTestManager; function onloaded(event) { var v = event.target; + v.removeEventListener("loadedmetadata", onloaded); v.currentTime = v.duration; return; } @@ -31,15 +32,18 @@ function checkNotPlaying(v) { ok(v.currentTime == 0, "Should not be playing after seek to end and back to beginning"); v._finished = true; manager.finished(v.token); + removeNodeAndSource(v); } function onseeked(event) { var v = event.target; + v.removeEventListener("seeked", onseeked); setTimeout(function() { checkNotPlaying(v); }, 500); } function onended(event) { var v = event.target; + v.removeEventListener("ended", onended); if (v._finished) return; v.addEventListener("seeked", onseeked, false); diff --git a/dom/media/test/test_paused_after_ended.html b/dom/media/test/test_paused_after_ended.html index 8b08d9436bb7..25fe7b5fdee5 100644 --- a/dom/media/test/test_paused_after_ended.html +++ b/dom/media/test/test_paused_after_ended.html @@ -14,13 +14,16 @@ var manager = new MediaTestManager; function ended(evt) { var v = evt.target; + v.removeEventListener("ended", ended); is(v.gotPause, true, "We should have received a \"pause\" event.") is(v.paused, true, v._name + " must be paused after end"); manager.finished(v.token); + removeNodeAndSource(v); } function pause(evt) { var v = evt.target; + v.removeEventListener("pause", pause); v.gotPause = true; } diff --git a/dom/media/test/test_streams_element_capture.html b/dom/media/test/test_streams_element_capture.html index 7d15d7fe952a..944d42b0d8bc 100644 --- a/dom/media/test/test_streams_element_capture.html +++ b/dom/media/test/test_streams_element_capture.html @@ -47,6 +47,7 @@ function startTest(test, token) { } vout.parentNode.removeChild(vout); manager.finished(vout.token); + removeNodeAndSource(v); }}(test, vout, stream); vout.addEventListener("ended", checkEnded, false); diff --git a/dom/media/webm/WebMBufferedParser.cpp b/dom/media/webm/WebMBufferedParser.cpp index 2c6244613133..ff3087e2c2d2 100644 --- a/dom/media/webm/WebMBufferedParser.cpp +++ b/dom/media/webm/WebMBufferedParser.cpp @@ -37,6 +37,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength, { static const uint32_t SEGMENT_ID = 0x18538067; static const uint32_t SEGINFO_ID = 0x1549a966; + static const uint32_t TRACKS_ID = 0x1654AE6B; static const uint32_t CLUSTER_ID = 0x1f43b675; static const uint32_t TIMECODESCALE_ID = 0x2ad7b1; static const unsigned char TIMECODE_ID = 0xe7; @@ -115,6 +116,10 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength, mState = READ_VINT; mNextState = READ_BLOCK_TIMECODE; break; + case TRACKS_ID: + mSkipBytes = mElement.mSize.mValue; + mState = CHECK_INIT_FOUND; + break; default: mSkipBytes = mElement.mSize.mValue; mState = SKIP_DATA; @@ -192,6 +197,20 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength, mState = mNextState; } break; + case CHECK_INIT_FOUND: + if (mSkipBytes) { + uint32_t left = aLength - (p - aBuffer); + left = std::min(left, mSkipBytes); + p += left; + mSkipBytes -= left; + } + if (!mSkipBytes) { + if (mInitEndOffset < 0) { + mInitEndOffset = mCurrentOffset + (p - aBuffer); + } + mState = READ_ELEMENT_ID; + } + break; } } @@ -321,6 +340,7 @@ void WebMBufferedState::NotifyDataArrived(const char* aBuffer, uint32_t aLength, while (i + 1 < mRangeParsers.Length()) { if (mRangeParsers[i].mCurrentOffset >= mRangeParsers[i + 1].mStartOffset) { mRangeParsers[i + 1].mStartOffset = mRangeParsers[i].mStartOffset; + mRangeParsers[i + 1].mInitEndOffset = mRangeParsers[i].mInitEndOffset; mRangeParsers.RemoveElementAt(i); } else { i += 1; @@ -328,5 +348,12 @@ void WebMBufferedState::NotifyDataArrived(const char* aBuffer, uint32_t aLength, } } -} // namespace mozilla +int64_t WebMBufferedState::GetInitEndOffset() +{ + if (mRangeParsers.IsEmpty()) { + return -1; + } + return mRangeParsers[0].mInitEndOffset; +} +} // namespace mozilla diff --git a/dom/media/webm/WebMBufferedParser.h b/dom/media/webm/WebMBufferedParser.h index 5e34585efc36..53a712c18836 100644 --- a/dom/media/webm/WebMBufferedParser.h +++ b/dom/media/webm/WebMBufferedParser.h @@ -50,9 +50,9 @@ struct WebMTimeDataOffset struct WebMBufferedParser { explicit WebMBufferedParser(int64_t aOffset) - : mStartOffset(aOffset), mCurrentOffset(aOffset), mState(READ_ELEMENT_ID), - mVIntRaw(false), mClusterSyncPos(0), mTimecodeScale(1000000), - mGotTimecodeScale(false) + : mStartOffset(aOffset), mCurrentOffset(aOffset), mInitEndOffset(-1), + mState(READ_ELEMENT_ID), mVIntRaw(false), mClusterSyncPos(0), + mTimecodeScale(1000000), mGotTimecodeScale(false) { if (mStartOffset != 0) { mState = FIND_CLUSTER_SYNC; @@ -95,6 +95,10 @@ struct WebMBufferedParser // data. int64_t mCurrentOffset; + // Tracks element's end offset. This indicates the end of the init segment. + // Will only be set if a Segment Information has been found. + int64_t mInitEndOffset; + private: enum State { // Parser start state. Expects to begin at a valid EBML element. Move @@ -140,6 +144,11 @@ private: // for this offset. READ_BLOCK_TIMECODE, + // Will skip the current tracks element and set mInitEndOffset if an init + // segment has been found. + // Currently, only assumes it's the end of the tracks element. + CHECK_INIT_FOUND, + // Skip mSkipBytes of data before resuming parse at mNextState. SKIP_DATA, }; @@ -232,6 +241,9 @@ public: // dependencies to arrive at aTime. bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); + // Returns end offset of init segment or -1 if none found. + int64_t GetInitEndOffset(); + private: // Private destructor, to discourage deletion outside of Release(): ~WebMBufferedState() { diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 75bc83a376e3..2d72cbc5efce 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -337,7 +337,7 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo, io.tell = webm_tell; io.userdata = mDecoder; int64_t maxOffset = mDecoder->HasInitializationData() ? - mDecoder->GetResource()->GetLength() : -1; + mBufferedState->GetInitEndOffset() : -1; int r = nestegg_init(&mContext, io, &webm_log, maxOffset); if (r == -1) { return NS_ERROR_FAILURE; diff --git a/dom/settings/SettingsRequestManager.jsm b/dom/settings/SettingsRequestManager.jsm index 52f10d933ca7..0edac13d65ce 100644 --- a/dom/settings/SettingsRequestManager.jsm +++ b/dom/settings/SettingsRequestManager.jsm @@ -8,7 +8,7 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; -this.EXPORTED_SYMBOLS = []; +this.EXPORTED_SYMBOLS = ["SettingsRequestManager"]; Cu.import("resource://gre/modules/SettingsDB.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -64,6 +64,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm", XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"); +XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", + "@mozilla.org/settingsService;1", + "nsISettingsService"); let SettingsPermissions = { checkPermission: function(aPrincipal, aPerm) { @@ -1036,10 +1039,18 @@ let SettingsRequestManager = { let mm = aMessage.target; function returnMessage(name, data) { - try { - mm.sendAsyncMessage(name, data); - } catch (e) { - if (DEBUG) debug("Return message failed, " + name); + if (mm) { + try { + mm.sendAsyncMessage(name, data); + } catch (e) { + if (DEBUG) debug("Return message failed, " + name + ": " + e); + } + } else { + try { + gSettingsService.receiveMessage({ name: name, data: data }); + } catch (e) { + if (DEBUG) debug("Direct return message failed, " + name + ": " + e); + } } } @@ -1193,4 +1204,5 @@ let SettingsRequestManager = { } }; +this.SettingsRequestManager = SettingsRequestManager; SettingsRequestManager.init(); diff --git a/dom/settings/SettingsService.js b/dom/settings/SettingsService.js index 09e96aea2a91..9e56b4fc5aec 100644 --- a/dom/settings/SettingsService.js +++ b/dom/settings/SettingsService.js @@ -79,10 +79,8 @@ function SettingsServiceLock(aSettingsService, aTransactionCallback) { windowID: undefined, lockStack: (new Error).stack }; - cpmm.sendAsyncMessage("Settings:CreateLock", - createLockPayload, - undefined, - Services.scriptSecurityManager.getSystemPrincipal()); + + this.returnMessage("Settings:CreateLock", createLockPayload); Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL); } @@ -91,12 +89,20 @@ SettingsServiceLock.prototype = { return !this._open; }, + returnMessage: function(aMessage, aData) { + SettingsRequestManager.receiveMessage({ + name: aMessage, + data: aData, + target: undefined, + principal: Services.scriptSecurityManager.getSystemPrincipal() + }); + }, + runOrFinalizeQueries: function() { if (!this._requests || Object.keys(this._requests).length == 0) { - this._settingsService.unregisterLock(this._id); - cpmm.sendAsyncMessage("Settings:Finalize", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal()); + this.returnMessage("Settings:Finalize", {lockID: this._id}); } else { - cpmm.sendAsyncMessage("Settings:Run", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal()); + this.returnMessage("Settings:Run", {lockID: this._id}); } }, @@ -124,6 +130,8 @@ SettingsServiceLock.prototype = { default: if (DEBUG) debug("Message type " + aMessage.name + " is missing a requestID"); } + + this._settingsService.unregisterLock(this._id); return; } @@ -138,7 +146,7 @@ SettingsServiceLock.prototype = { this._open = true; let settings_names = Object.keys(msg.settings); if (settings_names.length > 0) { - let name = settings_names[0]; + let name = settings_names[0]; if (DEBUG && settings_names.length > 1) { debug("Warning: overloaded setting:" + name); } @@ -174,11 +182,9 @@ SettingsServiceLock.prototype = { } let reqID = uuidgen.generateUUID().toString(); this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName); - cpmm.sendAsyncMessage("Settings:Get", {requestID: reqID, - lockID: this._id, - name: aName}, - undefined, - Services.scriptSecurityManager.getSystemPrincipal()); + this.returnMessage("Settings:Get", {requestID: reqID, + lockID: this._id, + name: aName}); }, set: function set(aName, aValue, aCallback) { @@ -190,11 +196,9 @@ SettingsServiceLock.prototype = { this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName, aValue); let settings = {}; settings[aName] = aValue; - cpmm.sendAsyncMessage("Settings:Set", {requestID: reqID, - lockID: this._id, - settings: settings}, - undefined, - Services.scriptSecurityManager.getSystemPrincipal()); + this.returnMessage("Settings:Set", {requestID: reqID, + lockID: this._id, + settings: settings}); }, callHandle: function callHandle(aCallback, aName, aValue) { @@ -239,6 +243,7 @@ function SettingsService() { if (VERBOSE) debug("settingsService Constructor"); this._locks = []; + this._serviceLocks = {}; this._createdLocks = 0; this._unregisteredLocks = 0; this.init(); @@ -263,14 +268,36 @@ SettingsService.prototype = { } }, + receiveMessage: function(aMessage) { + if (VERBOSE) debug("Entering receiveMessage"); + + let lockID = aMessage.data.lockID; + if (!lockID) { + if (DEBUG) debug("No lock ID"); + return; + } + + if (!(lockID in this._serviceLocks)) { + if (DEBUG) debug("Received message for lock " + lockID + " but no lock"); + return; + } + + if (VERBOSE) debug("Delivering message"); + this._serviceLocks[lockID].receiveMessage(aMessage); + }, + createLock: function createLock(aCallback) { + if (VERBOSE) debug("Calling createLock"); var lock = new SettingsServiceLock(this, aCallback); - this.registerLock(lock._id); + if (VERBOSE) debug("Created lock " + lock._id); + this.registerLock(lock); return lock; }, - registerLock: function(aLockID) { - this._locks.push(aLockID); + registerLock: function(aLock) { + if (VERBOSE) debug("Registering lock " + aLock._id); + this._locks.push(aLock._id); + this._serviceLocks[aLock._id] = aLock; this._createdLocks++; }, @@ -279,6 +306,8 @@ SettingsService.prototype = { if (lock_index != -1) { if (VERBOSE) debug("Unregistering lock " + aLockID); this._locks.splice(lock_index, 1); + this._serviceLocks[aLockID] = null; + delete this._serviceLocks[aLockID]; this._unregisteredLocks++; } }, diff --git a/gfx/layers/LayerScope.cpp b/gfx/layers/LayerScope.cpp index a266c778a5cf..2edf5d56a260 100644 --- a/gfx/layers/LayerScope.cpp +++ b/gfx/layers/LayerScope.cpp @@ -10,9 +10,11 @@ #include "nsAppRunner.h" #include "Composer2D.h" #include "Effects.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/Preferences.h" #include "mozilla/Endian.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/Preferences.h" +#include "mozilla/TimeStamp.h" + #include "TexturePoolOGL.h" #include "mozilla/layers/CompositorOGL.h" #include "mozilla/layers/CompositorParent.h" @@ -66,7 +68,8 @@ using namespace layerscope; class DebugDataSender; class DebugGLData; -/* This class handle websocket protocol which included +/* + * This class handle websocket protocol which included * handshake and data frame's header */ class LayerScopeWebSocketHandler : public nsIInputStreamCallback { @@ -81,203 +84,48 @@ public: LayerScopeWebSocketHandler() : mState(NoHandshake) + , mConnected(false) { } -private: - virtual ~LayerScopeWebSocketHandler() - { - if (mTransport) { - mTransport->Close(NS_OK); - } - } + void OpenStream(nsISocketTransport* aTransport); -public: - void OpenStream(nsISocketTransport* aTransport) { - MOZ_ASSERT(aTransport); - - mTransport = aTransport; - mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, - 0, - 0, - getter_AddRefs(mOutputStream)); - - nsCOMPtr debugInputStream; - mTransport->OpenInputStream(0, - 0, - 0, - getter_AddRefs(debugInputStream)); - mInputStream = do_QueryInterface(debugInputStream); - mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread()); - } - - bool WriteToStream(void *ptr, uint32_t size) { - if (mState == NoHandshake) { - // Not yet handshake, just return true in case of - // LayerScope remove this handle - return true; - } else if (mState == HandshakeFailed) { - return false; - } - - // Generate WebSocket header - uint8_t wsHeader[10]; - int wsHeaderSize = 0; - const uint8_t opcode = 0x2; - wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode; - if (size <= 125) { - wsHeaderSize = 2; - wsHeader[1] = size; - } else if (size < 65536) { - wsHeaderSize = 4; - wsHeader[1] = 0x7E; - NetworkEndian::writeUint16(wsHeader + 2, size); - } else { - wsHeaderSize = 10; - wsHeader[1] = 0x7F; - NetworkEndian::writeUint64(wsHeader + 2, size); - } - - // Send WebSocket header - nsresult rv; - uint32_t cnt; - rv = mOutputStream->Write(reinterpret_cast(wsHeader), - wsHeaderSize, &cnt); - if (NS_FAILED(rv)) - return false; - - uint32_t written = 0; - while (written < size) { - uint32_t cnt; - rv = mOutputStream->Write(reinterpret_cast(ptr) + written, - size - written, &cnt); - if (NS_FAILED(rv)) - return false; - - written += cnt; - } - - return true; - } + bool WriteToStream(void *aPtr, uint32_t aSize); // nsIInputStreamCallback - NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *stream) MOZ_OVERRIDE - { - nsTArray protocolString; - ReadInputStreamData(protocolString); + NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *aStream) MOZ_OVERRIDE; - if (WebSocketHandshake(protocolString)) { - mState = HandshakeSuccess; - } else { - mState = HandshakeFailed; - } - return NS_OK; - } private: - void ReadInputStreamData(nsTArray& aProtocolString) - { - nsLineBuffer lineBuffer; - nsCString line; - bool more = true; - do { - NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more); + virtual ~LayerScopeWebSocketHandler() { CloseConnection(); } - if (line.Length() > 0) { - aProtocolString.AppendElement(line); - } - } while (more && line.Length() > 0); - } + void ReadInputStreamData(nsTArray& aProtocolString); - bool WebSocketHandshake(nsTArray& aProtocolString) - { - nsresult rv; - bool isWebSocket = false; - nsCString version; - nsCString wsKey; - nsCString protocol; + bool WebSocketHandshake(nsTArray& aProtocolString); - // Validate WebSocket client request. - if (aProtocolString.Length() == 0) - return false; + nsresult HandleSocketMessage(nsIAsyncInputStream *aStream); - // Check that the HTTP method is GET - const char* HTTP_METHOD = "GET "; - if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) { - return false; - } + nsresult ProcessInput(uint8_t *aBuffer, uint32_t aCount); - for (uint32_t i = 1; i < aProtocolString.Length(); ++i) { - const char* line = aProtocolString[i].get(); - const char* prop_pos = strchr(line, ':'); - if (prop_pos != nullptr) { - nsCString key(line, prop_pos - line); - nsCString value(prop_pos + 2); - if (key.EqualsIgnoreCase("upgrade") && - value.EqualsIgnoreCase("websocket")) { - isWebSocket = true; - } else if (key.EqualsIgnoreCase("sec-websocket-version")) { - version = value; - } else if (key.EqualsIgnoreCase("sec-websocket-key")) { - wsKey = value; - } else if (key.EqualsIgnoreCase("sec-websocket-protocol")) { - protocol = value; - } - } - } + // Copied from WebsocketChannel, helper function to decode data frame + void ApplyMask(uint32_t aMask, uint8_t *aData, uint64_t aLen); - if (!isWebSocket) { - return false; - } + bool HandleDataFrame(uint8_t *aData, uint32_t aSize); - if (!(version.EqualsLiteral("7") || - version.EqualsLiteral("8") || - version.EqualsLiteral("13"))) { - return false; - } - - if (!(protocol.EqualsIgnoreCase("binary"))) { - return false; - } - - // Client request is valid. Start to generate and send server response. - nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); - nsAutoCString res; - SHA1Sum sha1; - nsCString combined(wsKey + guid); - sha1.update(combined.get(), combined.Length()); - uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long. - sha1.finish(digest); - nsCString newString(reinterpret_cast(digest), SHA1Sum::kHashSize); - Base64Encode(newString, res); - - nsCString response("HTTP/1.1 101 Switching Protocols\r\n"); - response.AppendLiteral("Upgrade: websocket\r\n"); - response.AppendLiteral("Connection: Upgrade\r\n"); - response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n")); - response.AppendLiteral("Sec-WebSocket-Protocol: binary\r\n\r\n"); - uint32_t written = 0; - uint32_t size = response.Length(); - while (written < size) { - uint32_t cnt; - rv = mOutputStream->Write(const_cast(response.get()) + written, - size - written, &cnt); - if (NS_FAILED(rv)) - return false; - - written += cnt; - } - mOutputStream->Flush(); - - return true; - } + void CloseConnection(); +private: nsCOMPtr mOutputStream; nsCOMPtr mInputStream; nsCOMPtr mTransport; SocketStateType mState; + bool mConnected; }; NS_IMPL_ISUPPORTS(LayerScopeWebSocketHandler, nsIInputStreamCallback); + +/* + * Manage Websocket connections + */ class LayerScopeWebSocketManager { public: LayerScopeWebSocketManager(); @@ -720,6 +568,12 @@ public: int aWidth = 0, int aHeight = 0); + static void SetLayersTreeSendable(bool aSet) {sLayersTreeSendable = aSet;} + + static void SetLayersBufferSendable(bool aSet) {sLayersBufferSendable = aSet;} + + static bool GetLayersTreeSendable() {return sLayersTreeSendable;} + // Sender private functions private: static void SendColor(void* aLayerRef, @@ -736,8 +590,16 @@ private: static void SendYCbCrEffect(GLContext* aGLContext, void* aLayerRef, const EffectYCbCr* aEffect); + +// Data fields +private: + static bool sLayersTreeSendable; + static bool sLayersBufferSendable; }; +bool SenderHelper::sLayersTreeSendable = true; +bool SenderHelper::sLayersBufferSendable = true; + // ---------------------------------------------- // SenderHelper implementation @@ -874,6 +736,8 @@ SenderHelper::SendEffectChain(GLContext* aGLContext, int aWidth, int aHeight) { + if (!sLayersBufferSendable) return; + const Effect* primaryEffect = aEffectChain.mPrimaryEffect; switch (primaryEffect->mType) { case EffectTypes::RGB: { @@ -908,6 +772,430 @@ SenderHelper::SendEffectChain(GLContext* aGLContext, // TODO: } + +// ---------------------------------------------- +// LayerScopeWebSocketHandler implementation +// ---------------------------------------------- +void +LayerScopeWebSocketHandler::OpenStream(nsISocketTransport* aTransport) +{ + MOZ_ASSERT(aTransport); + + mTransport = aTransport; + mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, + 0, + 0, + getter_AddRefs(mOutputStream)); + + nsCOMPtr debugInputStream; + mTransport->OpenInputStream(0, + 0, + 0, + getter_AddRefs(debugInputStream)); + mInputStream = do_QueryInterface(debugInputStream); + mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread()); +} + +bool +LayerScopeWebSocketHandler::WriteToStream(void *aPtr, + uint32_t aSize) +{ + if (mState == NoHandshake) { + // Not yet handshake, just return true in case of + // LayerScope remove this handle + return true; + } else if (mState == HandshakeFailed) { + return false; + } + + if (!mOutputStream) { + return false; + } + + // Generate WebSocket header + uint8_t wsHeader[10]; + int wsHeaderSize = 0; + const uint8_t opcode = 0x2; + wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode; + if (aSize <= 125) { + wsHeaderSize = 2; + wsHeader[1] = aSize; + } else if (aSize < 65536) { + wsHeaderSize = 4; + wsHeader[1] = 0x7E; + NetworkEndian::writeUint16(wsHeader + 2, aSize); + } else { + wsHeaderSize = 10; + wsHeader[1] = 0x7F; + NetworkEndian::writeUint64(wsHeader + 2, aSize); + } + + // Send WebSocket header + nsresult rv; + uint32_t cnt; + rv = mOutputStream->Write(reinterpret_cast(wsHeader), + wsHeaderSize, &cnt); + if (NS_FAILED(rv)) + return false; + + uint32_t written = 0; + while (written < aSize) { + uint32_t cnt; + rv = mOutputStream->Write(reinterpret_cast(aPtr) + written, + aSize - written, &cnt); + if (NS_FAILED(rv)) + return false; + + written += cnt; + } + + return true; +} + +NS_IMETHODIMP +LayerScopeWebSocketHandler::OnInputStreamReady(nsIAsyncInputStream *aStream) +{ + MOZ_ASSERT(mInputStream); + + if (!mInputStream) { + return NS_OK; + } + + if (!mConnected) { + nsTArray protocolString; + ReadInputStreamData(protocolString); + + if (WebSocketHandshake(protocolString)) { + mState = HandshakeSuccess; + mConnected = true; + mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread()); + } else { + mState = HandshakeFailed; + } + return NS_OK; + } else { + return HandleSocketMessage(aStream); + } +} + +void +LayerScopeWebSocketHandler::ReadInputStreamData(nsTArray& aProtocolString) +{ + nsLineBuffer lineBuffer; + nsCString line; + bool more = true; + do { + NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more); + + if (line.Length() > 0) { + aProtocolString.AppendElement(line); + } + } while (more && line.Length() > 0); +} + +bool +LayerScopeWebSocketHandler::WebSocketHandshake(nsTArray& aProtocolString) +{ + nsresult rv; + bool isWebSocket = false; + nsCString version; + nsCString wsKey; + nsCString protocol; + + // Validate WebSocket client request. + if (aProtocolString.Length() == 0) + return false; + + // Check that the HTTP method is GET + const char* HTTP_METHOD = "GET "; + if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) { + return false; + } + + for (uint32_t i = 1; i < aProtocolString.Length(); ++i) { + const char* line = aProtocolString[i].get(); + const char* prop_pos = strchr(line, ':'); + if (prop_pos != nullptr) { + nsCString key(line, prop_pos - line); + nsCString value(prop_pos + 2); + if (key.EqualsIgnoreCase("upgrade") && + value.EqualsIgnoreCase("websocket")) { + isWebSocket = true; + } else if (key.EqualsIgnoreCase("sec-websocket-version")) { + version = value; + } else if (key.EqualsIgnoreCase("sec-websocket-key")) { + wsKey = value; + } else if (key.EqualsIgnoreCase("sec-websocket-protocol")) { + protocol = value; + } + } + } + + if (!isWebSocket) { + return false; + } + + if (!(version.EqualsLiteral("7") || + version.EqualsLiteral("8") || + version.EqualsLiteral("13"))) { + return false; + } + + if (!(protocol.EqualsIgnoreCase("binary"))) { + return false; + } + + if (!mOutputStream) { + return false; + } + + // Client request is valid. Start to generate and send server response. + nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + nsAutoCString res; + SHA1Sum sha1; + nsCString combined(wsKey + guid); + sha1.update(combined.get(), combined.Length()); + uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long. + sha1.finish(digest); + nsCString newString(reinterpret_cast(digest), SHA1Sum::kHashSize); + Base64Encode(newString, res); + + nsCString response("HTTP/1.1 101 Switching Protocols\r\n"); + response.AppendLiteral("Upgrade: websocket\r\n"); + response.AppendLiteral("Connection: Upgrade\r\n"); + response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n")); + response.AppendLiteral("Sec-WebSocket-Protocol: binary\r\n\r\n"); + uint32_t written = 0; + uint32_t size = response.Length(); + while (written < size) { + uint32_t cnt; + rv = mOutputStream->Write(const_cast(response.get()) + written, + size - written, &cnt); + if (NS_FAILED(rv)) + return false; + + written += cnt; + } + mOutputStream->Flush(); + + return true; +} + +nsresult +LayerScopeWebSocketHandler::HandleSocketMessage(nsIAsyncInputStream *aStream) +{ + // The reading and parsing of this input stream is customized for layer viewer. + const uint32_t cPacketSize = 1024; + char buffer[cPacketSize]; + uint32_t count = 0; + nsresult rv = NS_OK; + + do { + rv = mInputStream->Read((char *)buffer, cPacketSize, &count); + + // TODO: combine packets if we have to read more than once + + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread()); + return NS_OK; + } + + if (NS_FAILED(rv)) { + break; + } + + if (count == 0) { + // NS_BASE_STREAM_CLOSED + CloseConnection(); + break; + } + + rv = ProcessInput(reinterpret_cast(buffer), count); + } while (NS_SUCCEEDED(rv) && mInputStream); + return rv; +} + +nsresult +LayerScopeWebSocketHandler::ProcessInput(uint8_t *aBuffer, + uint32_t aCount) +{ + uint32_t avail = aCount; + + // Decode Websocket data frame + if (avail <= 2) { + NS_WARNING("Packet size is less than 2 bytes"); + return NS_OK; + } + + // First byte, data type, only care the opcode + // rsvBits: aBuffer[0] & 0x70 (0111 0000) + uint8_t finBit = aBuffer[0] & 0x80; // 1000 0000 + uint8_t opcode = aBuffer[0] & 0x0F; // 0000 1111 + + if (!finBit) { + NS_WARNING("We cannot handle multi-fragments messages in Layerscope websocket parser."); + return NS_OK; + } + + // Second byte, data length + uint8_t maskBit = aBuffer[1] & 0x80; // 1000 0000 + int64_t payloadLength64 = aBuffer[1] & 0x7F; // 0111 1111 + + if (!maskBit) { + NS_WARNING("Client to Server should set the mask bit"); + return NS_OK; + } + + uint32_t framingLength = 2 + 4; // 4 for masks + + if (payloadLength64 < 126) { + if (avail < framingLength) + return NS_OK; + } else if (payloadLength64 == 126) { + // 16 bit length field + framingLength += 2; + if (avail < framingLength) { + return NS_OK; + } + + payloadLength64 = aBuffer[2] << 8 | aBuffer[3]; + } else { + // 64 bit length + framingLength += 8; + if (avail < framingLength) { + return NS_OK; + } + + if (aBuffer[2] & 0x80) { + // Section 4.2 says that the most significant bit MUST be + // 0. (i.e. this is really a 63 bit value) + NS_WARNING("High bit of 64 bit length set"); + return NS_ERROR_ILLEGAL_VALUE; + } + + // copy this in case it is unaligned + payloadLength64 = NetworkEndian::readInt64(aBuffer + 2); + } + + uint8_t *payload = aBuffer + framingLength; + avail -= framingLength; + + uint32_t payloadLength = static_cast(payloadLength64); + if (avail < payloadLength) { + NS_WARNING("Packet size mismatch the payload length"); + return NS_OK; + } + + // Apply mask + uint32_t mask = NetworkEndian::readUint32(payload - 4); + ApplyMask(mask, payload, payloadLength); + + if (opcode == 0x8) { + // opcode == 0x8 means connection close + CloseConnection(); + return NS_BASE_STREAM_CLOSED; + } + + if (!HandleDataFrame(payload, payloadLength)) { + NS_WARNING("Cannot decode payload data by the protocol buffer"); + } + + return NS_OK; +} + +void +LayerScopeWebSocketHandler::ApplyMask(uint32_t aMask, + uint8_t *aData, + uint64_t aLen) +{ + if (!aData || aLen == 0) { + return; + } + + // Optimally we want to apply the mask 32 bits at a time, + // but the buffer might not be alligned. So we first deal with + // 0 to 3 bytes of preamble individually + while (aLen && (reinterpret_cast(aData) & 3)) { + *aData ^= aMask >> 24; + aMask = RotateLeft(aMask, 8); + aData++; + aLen--; + } + + // perform mask on full words of data + uint32_t *iData = reinterpret_cast(aData); + uint32_t *end = iData + (aLen >> 2); + NetworkEndian::writeUint32(&aMask, aMask); + for (; iData < end; iData++) { + *iData ^= aMask; + } + aMask = NetworkEndian::readUint32(&aMask); + aData = (uint8_t *)iData; + aLen = aLen % 4; + + // There maybe up to 3 trailing bytes that need to be dealt with + // individually + while (aLen) { + *aData ^= aMask >> 24; + aMask = RotateLeft(aMask, 8); + aData++; + aLen--; + } +} + +bool +LayerScopeWebSocketHandler::HandleDataFrame(uint8_t *aData, + uint32_t aSize) +{ + // Handle payload data by protocol buffer + auto p = MakeUnique(); + p->ParseFromArray(static_cast(aData), aSize); + + if (!p->has_type()) { + MOZ_ASSERT(false, "Protocol buffer decoding failed or cannot recongize it"); + return false; + } + + switch (p->type()) { + case CommandPacket::LAYERS_TREE: + if (p->has_value()) { + SenderHelper::SetLayersTreeSendable(p->value()); + } + break; + + case CommandPacket::LAYERS_BUFFER: + if (p->has_value()) { + SenderHelper::SetLayersBufferSendable(p->value()); + } + break; + + case CommandPacket::NO_OP: + default: + NS_WARNING("Invalid message type"); + break; + } + return true; +} + +void +LayerScopeWebSocketHandler::CloseConnection() +{ + WebSocketHelper::GetSocketManager()->CleanDebugData(); + if (mInputStream) { + mInputStream->AsyncWait(nullptr, 0, 0, nullptr); + mInputStream = nullptr; + } + if (mOutputStream) { + mOutputStream = nullptr; + } + if (mTransport) { + mTransport->Close(NS_BASE_STREAM_CLOSED); + mTransport = nullptr; + } + mConnected = false; +} + + // ---------------------------------------------- // LayerScopeWebSocketManager implementation // ---------------------------------------------- @@ -923,6 +1211,7 @@ LayerScopeWebSocketManager::LayerScopeWebSocketManager() LayerScopeWebSocketManager::~LayerScopeWebSocketManager() { + mServerSocket->Close(); } void @@ -1005,7 +1294,7 @@ void LayerScope::SendLayerDump(UniquePtr aPacket) { // Protect this public function - if (!CheckSendable()) { + if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) { return; } WebSocketHelper::GetSocketManager()->AppendDebugData( diff --git a/gfx/layers/TiledLayerBuffer.h b/gfx/layers/TiledLayerBuffer.h index 9b1a42e9c4c0..2daf63f71398 100644 --- a/gfx/layers/TiledLayerBuffer.h +++ b/gfx/layers/TiledLayerBuffer.h @@ -546,15 +546,15 @@ TiledLayerBuffer::Update(const nsIntRegion& aNewValidRegion, x += width; } + mRetainedTiles = newRetainedTiles; AsDerived().PostValidate(aPaintRegion); - for (unsigned int i = 0; i < newRetainedTiles.Length(); ++i) { - AsDerived().UnlockTile(newRetainedTiles[i]); + for (unsigned int i = 0; i < mRetainedTiles.Length(); ++i) { + AsDerived().UnlockTile(mRetainedTiles[i]); } // At this point, oldTileCount should be zero NS_ABORT_IF_FALSE(oldTileCount == 0, "Failed to release old tiles"); - mRetainedTiles = newRetainedTiles; mValidRegion = aNewValidRegion; mPaintedRegion.Or(mPaintedRegion, aPaintRegion); } diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 6c6a3cb5d14b..9eb940a61b52 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -333,6 +333,9 @@ static TemporaryRef CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory) { RefPtr dest = factory->NewShSurfHandle(src->mSize); + if (!dest) { + return nullptr; + } SharedSurface::ProdCopy(src, dest->Surf(), factory); return dest.forget(); } diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index c6924cc31f27..afdf50dd3fcf 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -517,6 +517,7 @@ TileClient::TileClient(const TileClient& o) mManager = o.mManager; mInvalidFront = o.mInvalidFront; mInvalidBack = o.mInvalidBack; + mOrigin = o.mOrigin; } TileClient& @@ -536,6 +537,7 @@ TileClient::operator=(const TileClient& o) mManager = o.mManager; mInvalidFront = o.mInvalidFront; mInvalidBack = o.mInvalidBack; + mOrigin = o.mOrigin; return *this; } @@ -1056,6 +1058,31 @@ ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion) mTilingOrigin = IntPoint(std::numeric_limits::max(), std::numeric_limits::max()); } + + for (size_t i = 0; i < mRetainedTiles.Length(); ++i) { + TileClient& tile = mRetainedTiles[i]; + if (tile.mFrontBuffer && tile.mFrontBuffer->IsLocked()) { + // Only worry about padding when not doing low-res because it simplifies + // the math and the artifacts won't be noticable + // Edge padding prevents sampling artifacts when compositing. + if (mResolution == 1) { + nsIntRect unscaledTile = nsIntRect(tile.mOrigin.x, tile.mOrigin.y, + GetTileSize().width, GetTileSize().height); + nsIntRegion tileValidRegion = GetValidRegion(); + tileValidRegion.OrWith(aPaintRegion); + + // We only need to pad out if the tile has area that's not valid + if (!tileValidRegion.Contains(unscaledTile)) { + tileValidRegion = tileValidRegion.Intersect(unscaledTile); + // translate the region into tile space and pad + tileValidRegion.MoveBy(-nsIntPoint(unscaledTile.x, unscaledTile.y)); + RefPtr drawTarget = tile.mFrontBuffer->BorrowDrawTarget(); + PadDrawTargetOutFromRegion(drawTarget, tileValidRegion); + } + } + } + } + } void @@ -1144,6 +1171,8 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, } } + aTile.mOrigin = gfx::ToIntPoint(aTileOrigin); + if (usingTiledDrawTarget) { if (createdTextureClient) { if (!mCompositableClient->AddTextureClient(backBuffer)) { @@ -1247,26 +1276,6 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height)); } - // only worry about padding when not doing low-res - // because it simplifies the math and the artifacts - // won't be noticable - if (mResolution == 1) { - nsIntRect unscaledTile = nsIntRect(aTileOrigin.x, - aTileOrigin.y, - GetTileSize().width, - GetTileSize().height); - - nsIntRegion tileValidRegion = GetValidRegion(); - tileValidRegion.Or(tileValidRegion, aDirtyRegion); - // We only need to pad out if the tile has area that's not valid - if (!tileValidRegion.Contains(unscaledTile)) { - tileValidRegion = tileValidRegion.Intersect(unscaledTile); - // translate the region into tile space and pad - tileValidRegion.MoveBy(-nsIntPoint(unscaledTile.x, unscaledTile.y)); - PadDrawTargetOutFromRegion(drawTarget, tileValidRegion); - } - } - // The new buffer is now validated, remove the dirty region from it. aTile.mInvalidBack.SubOut(offsetScaledDirtyRegion); diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 639fdb0c7dad..d86a9feebee3 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -274,6 +274,8 @@ struct TileClient nsIntRegion mInvalidBack; nsExpirationState mExpirationState; + gfx::IntPoint mOrigin; + private: // Copies dirty pixels from the front buffer into the back buffer, // and records the copied region in aAddPaintedRegion. diff --git a/gfx/layers/protobuf/LayerScopePacket.pb.cc b/gfx/layers/protobuf/LayerScopePacket.pb.cc index 45251c76defa..3c07257b296f 100644 --- a/gfx/layers/protobuf/LayerScopePacket.pb.cc +++ b/gfx/layers/protobuf/LayerScopePacket.pb.cc @@ -27,6 +27,7 @@ void protobuf_ShutdownFile_LayerScopePacket_2eproto() { delete LayersPacket_Layer_Shadow::default_instance_; delete MetaPacket::default_instance_; delete Packet::default_instance_; + delete CommandPacket::default_instance_; } void protobuf_AddDesc_LayerScopePacket_2eproto() { @@ -47,6 +48,7 @@ void protobuf_AddDesc_LayerScopePacket_2eproto() { LayersPacket_Layer_Shadow::default_instance_ = new LayersPacket_Layer_Shadow(); MetaPacket::default_instance_ = new MetaPacket(); Packet::default_instance_ = new Packet(); + CommandPacket::default_instance_ = new CommandPacket(); FramePacket::default_instance_->InitAsDefaultInstance(); ColorPacket::default_instance_->InitAsDefaultInstance(); TexturePacket::default_instance_->InitAsDefaultInstance(); @@ -59,6 +61,7 @@ void protobuf_AddDesc_LayerScopePacket_2eproto() { LayersPacket_Layer_Shadow::default_instance_->InitAsDefaultInstance(); MetaPacket::default_instance_->InitAsDefaultInstance(); Packet::default_instance_->InitAsDefaultInstance(); + CommandPacket::default_instance_->InitAsDefaultInstance(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_LayerScopePacket_2eproto); } @@ -3573,6 +3576,220 @@ void Packet::Swap(Packet* other) { } +// =================================================================== + +bool CommandPacket_CmdType_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const CommandPacket_CmdType CommandPacket::NO_OP; +const CommandPacket_CmdType CommandPacket::LAYERS_TREE; +const CommandPacket_CmdType CommandPacket::LAYERS_BUFFER; +const CommandPacket_CmdType CommandPacket::CmdType_MIN; +const CommandPacket_CmdType CommandPacket::CmdType_MAX; +const int CommandPacket::CmdType_ARRAYSIZE; +#endif // _MSC_VER +#ifndef _MSC_VER +const int CommandPacket::kTypeFieldNumber; +const int CommandPacket::kValueFieldNumber; +#endif // !_MSC_VER + +CommandPacket::CommandPacket() + : ::google::protobuf::MessageLite() { + SharedCtor(); +} + +void CommandPacket::InitAsDefaultInstance() { +} + +CommandPacket::CommandPacket(const CommandPacket& from) + : ::google::protobuf::MessageLite() { + SharedCtor(); + MergeFrom(from); +} + +void CommandPacket::SharedCtor() { + _cached_size_ = 0; + type_ = 0; + value_ = false; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CommandPacket::~CommandPacket() { + SharedDtor(); +} + +void CommandPacket::SharedDtor() { + if (this != default_instance_) { + } +} + +void CommandPacket::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const CommandPacket& CommandPacket::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto(); return *default_instance_; +} + +CommandPacket* CommandPacket::default_instance_ = NULL; + +CommandPacket* CommandPacket::New() const { + return new CommandPacket; +} + +void CommandPacket::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + type_ = 0; + value_ = false; + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +bool CommandPacket::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::mozilla::layers::layerscope::CommandPacket_CmdType_IsValid(value)) { + set_type(static_cast< ::mozilla::layers::layerscope::CommandPacket_CmdType >(value)); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_value; + break; + } + + // optional bool value = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &value_))); + set_has_value(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } + return true; +#undef DO_ +} + +void CommandPacket::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1; + if (has_type()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 1, this->type(), output); + } + + // optional bool value = 2; + if (has_value()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->value(), output); + } + +} + +int CommandPacket::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1; + if (has_type()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->type()); + } + + // optional bool value = 2; + if (has_value()) { + total_size += 1 + 1; + } + + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CommandPacket::CheckTypeAndMergeFrom( + const ::google::protobuf::MessageLite& from) { + MergeFrom(*::google::protobuf::down_cast(&from)); +} + +void CommandPacket::MergeFrom(const CommandPacket& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_type()) { + set_type(from.type()); + } + if (from.has_value()) { + set_value(from.value()); + } + } +} + +void CommandPacket::CopyFrom(const CommandPacket& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CommandPacket::IsInitialized() const { + if ((_has_bits_[0] & 0x00000001) != 0x00000001) return false; + + return true; +} + +void CommandPacket::Swap(CommandPacket* other) { + if (other != this) { + std::swap(type_, other->type_); + std::swap(value_, other->value_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::std::string CommandPacket::GetTypeName() const { + return "mozilla.layers.layerscope.CommandPacket"; +} + + // @@protoc_insertion_point(namespace_scope) } // namespace layerscope diff --git a/gfx/layers/protobuf/LayerScopePacket.pb.h b/gfx/layers/protobuf/LayerScopePacket.pb.h index cc0d5ebfe08d..4f49ba9a7bcd 100644 --- a/gfx/layers/protobuf/LayerScopePacket.pb.h +++ b/gfx/layers/protobuf/LayerScopePacket.pb.h @@ -45,6 +45,7 @@ class LayersPacket_Layer_Matrix; class LayersPacket_Layer_Shadow; class MetaPacket; class Packet; +class CommandPacket; enum LayersPacket_Layer_LayerType { LayersPacket_Layer_LayerType_UnknownLayer = 0, @@ -98,6 +99,16 @@ const Packet_DataType Packet_DataType_DataType_MIN = Packet_DataType_FRAMESTART; const Packet_DataType Packet_DataType_DataType_MAX = Packet_DataType_META; const int Packet_DataType_DataType_ARRAYSIZE = Packet_DataType_DataType_MAX + 1; +enum CommandPacket_CmdType { + CommandPacket_CmdType_NO_OP = 0, + CommandPacket_CmdType_LAYERS_TREE = 1, + CommandPacket_CmdType_LAYERS_BUFFER = 2 +}; +bool CommandPacket_CmdType_IsValid(int value); +const CommandPacket_CmdType CommandPacket_CmdType_CmdType_MIN = CommandPacket_CmdType_NO_OP; +const CommandPacket_CmdType CommandPacket_CmdType_CmdType_MAX = CommandPacket_CmdType_LAYERS_BUFFER; +const int CommandPacket_CmdType_CmdType_ARRAYSIZE = CommandPacket_CmdType_CmdType_MAX + 1; + // =================================================================== class FramePacket : public ::google::protobuf::MessageLite { @@ -1439,6 +1450,99 @@ class Packet : public ::google::protobuf::MessageLite { void InitAsDefaultInstance(); static Packet* default_instance_; }; +// ------------------------------------------------------------------- + +class CommandPacket : public ::google::protobuf::MessageLite { + public: + CommandPacket(); + virtual ~CommandPacket(); + + CommandPacket(const CommandPacket& from); + + inline CommandPacket& operator=(const CommandPacket& from) { + CopyFrom(from); + return *this; + } + + static const CommandPacket& default_instance(); + + void Swap(CommandPacket* other); + + // implements Message ---------------------------------------------- + + CommandPacket* New() const; + void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); + void CopyFrom(const CommandPacket& from); + void MergeFrom(const CommandPacket& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::std::string GetTypeName() const; + + // nested types ---------------------------------------------------- + + typedef CommandPacket_CmdType CmdType; + static const CmdType NO_OP = CommandPacket_CmdType_NO_OP; + static const CmdType LAYERS_TREE = CommandPacket_CmdType_LAYERS_TREE; + static const CmdType LAYERS_BUFFER = CommandPacket_CmdType_LAYERS_BUFFER; + static inline bool CmdType_IsValid(int value) { + return CommandPacket_CmdType_IsValid(value); + } + static const CmdType CmdType_MIN = + CommandPacket_CmdType_CmdType_MIN; + static const CmdType CmdType_MAX = + CommandPacket_CmdType_CmdType_MAX; + static const int CmdType_ARRAYSIZE = + CommandPacket_CmdType_CmdType_ARRAYSIZE; + + // accessors ------------------------------------------------------- + + // required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1; + inline bool has_type() const; + inline void clear_type(); + static const int kTypeFieldNumber = 1; + inline ::mozilla::layers::layerscope::CommandPacket_CmdType type() const; + inline void set_type(::mozilla::layers::layerscope::CommandPacket_CmdType value); + + // optional bool value = 2; + inline bool has_value() const; + inline void clear_value(); + static const int kValueFieldNumber = 2; + inline bool value() const; + inline void set_value(bool value); + + // @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.CommandPacket) + private: + inline void set_has_type(); + inline void clear_has_type(); + inline void set_has_value(); + inline void clear_has_value(); + + int type_; + bool value_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void protobuf_AddDesc_LayerScopePacket_2eproto(); + friend void protobuf_AssignDesc_LayerScopePacket_2eproto(); + friend void protobuf_ShutdownFile_LayerScopePacket_2eproto(); + + void InitAsDefaultInstance(); + static CommandPacket* default_instance_; +}; // =================================================================== @@ -2803,6 +2907,55 @@ inline ::mozilla::layers::layerscope::MetaPacket* Packet::release_meta() { return temp; } +// ------------------------------------------------------------------- + +// CommandPacket + +// required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1; +inline bool CommandPacket::has_type() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void CommandPacket::set_has_type() { + _has_bits_[0] |= 0x00000001u; +} +inline void CommandPacket::clear_has_type() { + _has_bits_[0] &= ~0x00000001u; +} +inline void CommandPacket::clear_type() { + type_ = 0; + clear_has_type(); +} +inline ::mozilla::layers::layerscope::CommandPacket_CmdType CommandPacket::type() const { + return static_cast< ::mozilla::layers::layerscope::CommandPacket_CmdType >(type_); +} +inline void CommandPacket::set_type(::mozilla::layers::layerscope::CommandPacket_CmdType value) { + GOOGLE_DCHECK(::mozilla::layers::layerscope::CommandPacket_CmdType_IsValid(value)); + set_has_type(); + type_ = value; +} + +// optional bool value = 2; +inline bool CommandPacket::has_value() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void CommandPacket::set_has_value() { + _has_bits_[0] |= 0x00000002u; +} +inline void CommandPacket::clear_has_value() { + _has_bits_[0] &= ~0x00000002u; +} +inline void CommandPacket::clear_value() { + value_ = false; + clear_has_value(); +} +inline bool CommandPacket::value() const { + return value_; +} +inline void CommandPacket::set_value(bool value) { + set_has_value(); + value_ = value; +} + // @@protoc_insertion_point(namespace_scope) diff --git a/gfx/layers/protobuf/LayerScopePacket.proto b/gfx/layers/protobuf/LayerScopePacket.proto index e167991d9464..11341e216ef2 100644 --- a/gfx/layers/protobuf/LayerScopePacket.proto +++ b/gfx/layers/protobuf/LayerScopePacket.proto @@ -4,6 +4,9 @@ option optimize_for = LITE_RUNTIME; package mozilla.layers.layerscope; +// =============================== +// Server to Client messages +// =============================== message FramePacket { optional uint64 value = 1; } @@ -133,3 +136,17 @@ message Packet { optional LayersPacket layers = 5; optional MetaPacket meta = 6; } + + +// =============================== +// Client to Server messages +// =============================== +message CommandPacket { + enum CmdType { + NO_OP = 0; + LAYERS_TREE = 1; + LAYERS_BUFFER = 2; + } + required CmdType type = 1; + optional bool value = 2; +} diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 61a59030e723..e3b30a8b15c8 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include "HalImpl.h" #include "HalLog.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/battery/Constants.h" #include "mozilla/DebugOnly.h" #include "mozilla/FileUtils.h" @@ -628,28 +630,6 @@ namespace { /** * RAII class to help us remember to close file descriptors. */ -const char *wakeLockFilename = "/sys/power/wake_lock"; -const char *wakeUnlockFilename = "/sys/power/wake_unlock"; - -template -bool ReadFromFile(const char *filename, char (&buf)[n]) -{ - int fd = open(filename, O_RDONLY); - ScopedClose autoClose(fd); - if (fd < 0) { - HAL_LOG("Unable to open file %s.", filename); - return false; - } - - ssize_t numRead = read(fd, buf, n); - if (numRead < 0) { - HAL_LOG("Error reading from file %s.", filename); - return false; - } - - buf[std::min(numRead, n - 1)] = '\0'; - return true; -} bool WriteToFile(const char *filename, const char *toWrite) { @@ -775,6 +755,9 @@ static Monitor* sInternalLockCpuMonitor = nullptr; static void UpdateCpuSleepState() { + const char *wakeLockFilename = "/sys/power/wake_lock"; + const char *wakeUnlockFilename = "/sys/power/wake_unlock"; + sInternalLockCpuMonitor->AssertCurrentThreadOwns(); bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount; WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko"); @@ -1286,7 +1269,6 @@ OomVictimLogger::Observe( lineTimestampFound = true; mLastLineChecked = lineTimestamp; } - // Log interesting lines for (size_t i = 0; i < regex_count; i++) { @@ -1312,6 +1294,261 @@ OomVictimLogger::Observe( return NS_OK; } +/** + * Wraps a particular ProcessPriority, giving us easy access to the prefs that + * are relevant to it. + * + * Creating a PriorityClass also ensures that the control group is created. + */ +class PriorityClass +{ +public: + /** + * Create a PriorityClass for the given ProcessPriority. This implicitly + * reads the relevant prefs and opens the cgroup.procs file of the relevant + * control group caching its file descriptor for later use. + */ + PriorityClass(ProcessPriority aPriority); + + /** + * Closes the file descriptor for the cgroup.procs file of the associated + * control group. + */ + ~PriorityClass(); + + PriorityClass(const PriorityClass& aOther); + PriorityClass& operator=(const PriorityClass& aOther); + + ProcessPriority Priority() + { + return mPriority; + } + + int32_t OomScoreAdj() + { + return clamped(mOomScoreAdj, OOM_SCORE_ADJ_MIN, OOM_SCORE_ADJ_MAX); + } + + int32_t KillUnderKB() + { + return mKillUnderKB; + } + + nsCString CGroup() + { + return mGroup; + } + + /** + * Adds a process to this priority class, this moves the process' PID into + * the associated control group. + * + * @param aPid The PID of the process to be added. + */ + void AddProcess(int aPid); + +private: + ProcessPriority mPriority; + int32_t mOomScoreAdj; + int32_t mKillUnderKB; + int mCGroupProcsFd; + nsCString mGroup; + + /** + * Return a string that identifies where we can find the value of aPref + * that's specific to mPriority. For example, we might return + * "hal.processPriorityManager.gonk.FOREGROUND_HIGH.oomScoreAdjust". + */ + nsCString PriorityPrefName(const char* aPref) + { + return nsPrintfCString("hal.processPriorityManager.gonk.%s.%s", + ProcessPriorityToString(mPriority), aPref); + } + + /** + * Get the full path of the cgroup.procs file associated with the group. + */ + nsCString CGroupProcsFilename() + { + nsCString cgroupName = mGroup; + + /* If mGroup is empty, our cgroup.procs file is the root procs file, + * located at /dev/cpuctl/cgroup.procs. Otherwise our procs file is + * /dev/cpuctl/NAME/cgroup.procs. */ + + if (!mGroup.IsEmpty()) { + cgroupName.AppendLiteral("/"); + } + + return NS_LITERAL_CSTRING("/dev/cpuctl/") + cgroupName + + NS_LITERAL_CSTRING("cgroup.procs"); + } + + int OpenCGroupProcs() + { + return open(CGroupProcsFilename().get(), O_WRONLY); + } +}; + +/** + * Try to create the cgroup for the given PriorityClass, if it doesn't already + * exist. This essentially implements mkdir -p; that is, we create parent + * cgroups as necessary. The group parameters are also set according to + * the corresponding preferences. + * + * @param aGroup The name of the group. + * @return true if we successfully created the cgroup, or if it already + * exists. Otherwise, return false. + */ +static bool +EnsureCGroupExists(const nsACString &aGroup) +{ + NS_NAMED_LITERAL_CSTRING(kDevCpuCtl, "/dev/cpuctl/"); + NS_NAMED_LITERAL_CSTRING(kSlash, "/"); + + nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups."); + + /* If cgroup is not empty, append the cgroup name and a dot to obtain the + * group specific preferences. */ + if (!aGroup.IsEmpty()) { + prefPrefix += aGroup + NS_LITERAL_CSTRING("."); + } + + nsAutoCString cpuSharesPref(prefPrefix + NS_LITERAL_CSTRING("cpu_shares")); + int cpuShares = Preferences::GetInt(cpuSharesPref.get()); + + nsAutoCString cpuNotifyOnMigratePref(prefPrefix + + NS_LITERAL_CSTRING("cpu_notify_on_migrate")); + int cpuNotifyOnMigrate = Preferences::GetInt(cpuNotifyOnMigratePref.get()); + + // Create mCGroup and its parent directories, as necessary. + nsCString cgroupIter = aGroup + kSlash; + + int32_t offset = 0; + while ((offset = cgroupIter.FindChar('/', offset)) != -1) { + nsAutoCString path = kDevCpuCtl + Substring(cgroupIter, 0, offset); + int rv = mkdir(path.get(), 0744); + + if (rv == -1 && errno != EEXIST) { + HAL_LOG("Could not create the %s control group.", path.get()); + return false; + } + + offset++; + } + + nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash); + nsAutoCString cpuSharesPath(pathPrefix + NS_LITERAL_CSTRING("cpu.shares")); + if (cpuShares && !WriteToFile(cpuSharesPath.get(), + nsPrintfCString("%d", cpuShares).get())) { + HAL_LOG("Could not set the cpu share for group %s", cpuSharesPath.get()); + return false; + } + + nsAutoCString notifyOnMigratePath(pathPrefix + + NS_LITERAL_CSTRING("cpu.notify_on_migrate")); + if (!WriteToFile(notifyOnMigratePath.get(), + nsPrintfCString("%d", cpuNotifyOnMigrate).get())) { + HAL_LOG("Could not set the cpu migration notification flag for group %s", + notifyOnMigratePath.get()); + return false; + } + + return true; +} + +PriorityClass::PriorityClass(ProcessPriority aPriority) + : mPriority(aPriority) + , mOomScoreAdj(0) + , mKillUnderKB(0) + , mCGroupProcsFd(-1) +{ + DebugOnly rv; + + rv = Preferences::GetInt(PriorityPrefName("OomScoreAdjust").get(), + &mOomScoreAdj); + MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing oom_score_adj preference"); + + rv = Preferences::GetInt(PriorityPrefName("KillUnderKB").get(), + &mKillUnderKB); + + rv = Preferences::GetCString(PriorityPrefName("cgroup").get(), &mGroup); + MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing control group preference"); + + if (EnsureCGroupExists(mGroup)) { + mCGroupProcsFd = OpenCGroupProcs(); + } +} + +PriorityClass::~PriorityClass() +{ + close(mCGroupProcsFd); +} + +PriorityClass::PriorityClass(const PriorityClass& aOther) + : mPriority(aOther.mPriority) + , mOomScoreAdj(aOther.mOomScoreAdj) + , mKillUnderKB(aOther.mKillUnderKB) + , mGroup(aOther.mGroup) +{ + mCGroupProcsFd = OpenCGroupProcs(); +} + +PriorityClass& PriorityClass::operator=(const PriorityClass& aOther) +{ + mPriority = aOther.mPriority; + mOomScoreAdj = aOther.mOomScoreAdj; + mKillUnderKB = aOther.mKillUnderKB; + mGroup = aOther.mGroup; + mCGroupProcsFd = OpenCGroupProcs(); + return *this; +} + +void PriorityClass::AddProcess(int aPid) +{ + if (mCGroupProcsFd < 0) { + return; + } + + nsPrintfCString str("%d", aPid); + + if (write(mCGroupProcsFd, str.get(), strlen(str.get())) < 0) { + HAL_ERR("Couldn't add PID %d to the %s control group", aPid, mGroup.get()); + } +} + +/** + * Get the PriorityClass associated with the given ProcessPriority. + * + * If you pass an invalid ProcessPriority value, we return null. + * + * The pointers returned here are owned by GetPriorityClass (don't free them + * yourself). They are guaranteed to stick around until shutdown. + */ +PriorityClass* +GetPriorityClass(ProcessPriority aPriority) +{ + static StaticAutoPtr> priorityClasses; + + // Initialize priorityClasses if this is the first time we're running this + // method. + if (!priorityClasses) { + priorityClasses = new nsTArray(); + ClearOnShutdown(&priorityClasses); + + for (int32_t i = 0; i < NUM_PROCESS_PRIORITY; i++) { + priorityClasses->AppendElement(PriorityClass(ProcessPriority(i))); + } + } + + if (aPriority < 0 || + static_cast(aPriority) >= priorityClasses->Length()) { + return nullptr; + } + + return &(*priorityClasses)[aPriority]; +} + static void EnsureKernelLowMemKillerParamsSet() { @@ -1352,21 +1589,12 @@ EnsureKernelLowMemKillerParamsSet() // The system doesn't function correctly if we're missing these prefs, so // crash loudly. - ProcessPriority priority = static_cast(i); + PriorityClass* pc = GetPriorityClass(static_cast(i)); - int32_t oomScoreAdj; - if (!NS_SUCCEEDED(Preferences::GetInt( - nsPrintfCString("hal.processPriorityManager.gonk.%s.OomScoreAdjust", - ProcessPriorityToString(priority)).get(), - &oomScoreAdj))) { - MOZ_CRASH(); - } + int32_t oomScoreAdj = pc->OomScoreAdj(); + int32_t killUnderKB = pc->KillUnderKB(); - int32_t killUnderKB; - if (!NS_SUCCEEDED(Preferences::GetInt( - nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB", - ProcessPriorityToString(priority)).get(), - &killUnderKB))) { + if (killUnderKB == 0) { // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD, // which has only OomScoreAdjust but lacks KillUnderMB value, will not // create new LMK parameters. @@ -1397,7 +1625,8 @@ EnsureKernelLowMemKillerParamsSet() minfreeParams.Cut(minfreeParams.Length() - 1, 1); if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) { WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get()); - WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", minfreeParams.get()); + WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", + minfreeParams.get()); } // Set the low-memory-notification threshold. @@ -1419,148 +1648,6 @@ EnsureKernelLowMemKillerParamsSet() } } -static void -SetNiceForPid(int aPid, int aNice) -{ - errno = 0; - int origProcPriority = getpriority(PRIO_PROCESS, aPid); - if (errno) { - HAL_LOG("Unable to get nice for pid=%d; error %d. SetNiceForPid bailing.", - aPid, errno); - return; - } - - int rv = setpriority(PRIO_PROCESS, aPid, aNice); - if (rv) { - HAL_LOG("Unable to set nice for pid=%d; error %d. SetNiceForPid bailing.", - aPid, errno); - return; - } - - // On Linux, setpriority(aPid) modifies the priority only of the main - // thread of that process. We have to modify the priorities of all of the - // process's threads as well, so iterate over all the threads and increase - // each of their priorites by aNice - origProcPriority (and also ensure that - // none of the tasks has a lower priority than the main thread). - // - // This is horribly racy. - - DIR* tasksDir = opendir(nsPrintfCString("/proc/%d/task/", aPid).get()); - if (!tasksDir) { - HAL_LOG("Unable to open /proc/%d/task. SetNiceForPid bailing.", aPid); - return; - } - - // Be careful not to leak tasksDir; after this point, we must call closedir(). - - while (struct dirent* de = readdir(tasksDir)) { - char* endptr = nullptr; - long tidlong = strtol(de->d_name, &endptr, /* base */ 10); - if (*endptr || tidlong < 0 || tidlong > INT32_MAX || tidlong == aPid) { - // if dp->d_name was not an integer, was negative (?!) or too large, or - // was the same as aPid, we're not interested. - // - // (The |tidlong == aPid| check is very important; without it, we'll - // renice aPid twice, and the second renice will be relative to the - // priority set by the first renice.) - continue; - } - - int tid = static_cast(tidlong); - - // Do not set the priority of threads running with a real-time policy - // as part of the bulk process adjustment. These threads need to run - // at their specified priority in order to meet timing guarantees. - int schedPolicy = sched_getscheduler(tid); - if (schedPolicy == SCHED_FIFO || schedPolicy == SCHED_RR) { - continue; - } - - errno = 0; - // Get and set the task's new priority. - int origtaskpriority = getpriority(PRIO_PROCESS, tid); - if (errno) { - HAL_LOG("Unable to get nice for tid=%d (pid=%d); error %d. This isn't " - "necessarily a problem; it could be a benign race condition.", - tid, aPid, errno); - continue; - } - - int newtaskpriority = - std::max(origtaskpriority - origProcPriority + aNice, aNice); - - // Do not reduce priority of threads already running at priorities greater - // than normal. These threads are likely special service threads that need - // elevated priorities to process audio, display composition, etc. - if (newtaskpriority > origtaskpriority && - origtaskpriority < ANDROID_PRIORITY_NORMAL) { - continue; - } - - rv = setpriority(PRIO_PROCESS, tid, newtaskpriority); - - if (rv) { - HAL_LOG("Unable to set nice for tid=%d (pid=%d); error %d. This isn't " - "necessarily a problem; it could be a benign race condition.", - tid, aPid, errno); - continue; - } - } - - HAL_LOG("Changed nice for pid %d from %d to %d.", - aPid, origProcPriority, aNice); - - closedir(tasksDir); -} - -/* - * Used to store the nice value adjustments and oom_adj values for the various - * process priority levels. - */ -struct ProcessPriorityPrefs { - bool initialized; - int lowPriorityNice; - struct { - int nice; - int oomScoreAdj; - } priorities[NUM_PROCESS_PRIORITY]; -}; - -/* - * Reads the preferences for the various process priority levels and sets up - * watchers so that if they're dynamically changed the change is reflected on - * the appropriate variables. - */ -void -EnsureProcessPriorityPrefs(ProcessPriorityPrefs* prefs) -{ - if (prefs->initialized) { - return; - } - - // Read the preferences for process priority levels - for (int i = PROCESS_PRIORITY_BACKGROUND; i < NUM_PROCESS_PRIORITY; i++) { - ProcessPriority priority = static_cast(i); - - // Read the nice values - const char* processPriorityStr = ProcessPriorityToString(priority); - nsPrintfCString niceStr("hal.processPriorityManager.gonk.%s.Nice", - processPriorityStr); - Preferences::AddIntVarCache(&prefs->priorities[i].nice, niceStr.get()); - - // Read the oom_adj scores - nsPrintfCString oomStr("hal.processPriorityManager.gonk.%s.OomScoreAdjust", - processPriorityStr); - Preferences::AddIntVarCache(&prefs->priorities[i].oomScoreAdj, - oomStr.get()); - } - - Preferences::AddIntVarCache(&prefs->lowPriorityNice, - "hal.processPriorityManager.gonk.LowCPUNice"); - - prefs->initialized = true; -} - void SetProcessPriority(int aPid, ProcessPriority aPriority, @@ -1579,49 +1666,23 @@ SetProcessPriority(int aPid, // SetProcessPriority being called early in startup. EnsureKernelLowMemKillerParamsSet(); - static ProcessPriorityPrefs prefs = { 0 }; - EnsureProcessPriorityPrefs(&prefs); + PriorityClass* pc = GetPriorityClass(aPriority); - int oomScoreAdj = prefs.priorities[aPriority].oomScoreAdj; + int oomScoreAdj = pc->OomScoreAdj(); RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU); - int clampedOomScoreAdj = clamped(oomScoreAdj, OOM_SCORE_ADJ_MIN, - OOM_SCORE_ADJ_MAX); - if (clampedOomScoreAdj != oomScoreAdj) { - HAL_LOG("Clamping OOM adjustment for pid %d to %d", aPid, - clampedOomScoreAdj); - } else { - HAL_LOG("Setting OOM adjustment for pid %d to %d", aPid, - clampedOomScoreAdj); - } - // We try the newer interface first, and fall back to the older interface // on failure. - if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(), - nsPrintfCString("%d", clampedOomScoreAdj).get())) + nsPrintfCString("%d", oomScoreAdj).get())) { - int oomAdj = OomAdjOfOomScoreAdj(clampedOomScoreAdj); - WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(), - nsPrintfCString("%d", oomAdj).get()); + nsPrintfCString("%d", OomAdjOfOomScoreAdj(oomScoreAdj)).get()); } - int nice = 0; - - if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) { - nice = prefs.priorities[aPriority].nice; - } else if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) { - nice = prefs.lowPriorityNice; - } else { - HAL_ERR("Unknown aCPUPriority value %d", aCPUPriority); - MOZ_ASSERT(false); - return; - } - - HAL_LOG("Setting nice for pid %d to %d", aPid, nice); - SetNiceForPid(aPid, nice); + HAL_LOG("Assigning pid %d to cgroup %s", aPid, pc->CGroup().get()); + pc->AddProcess(aPid); } static bool diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 5b607e5acda2..07eb390957be 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -809,16 +809,24 @@ js::atomics_futexWait(JSContext *cx, unsigned argc, Value *vp) case JS::PerRuntimeFutexAPI::Timedout: r.setInt32(AtomicsObject::FutexTimedout); break; - case JS::PerRuntimeFutexAPI::ErrorTooLong: - // This is a hack, but it's serviceable. - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ATOMICS_TOO_LONG); + case JS::PerRuntimeFutexAPI::ErrorException: + MOZ_ASSERT(JS_IsExceptionPending(cx)); retval = false; break; case JS::PerRuntimeFutexAPI::InterruptForTerminate: - // Throw an uncatchable exception. JS_ClearPendingException(cx); retval = false; break; + case JS::PerRuntimeFutexAPI::WaitingNotAllowed: + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ATOMICS_WAIT_NOT_ALLOWED); + retval = false; + break; + case JS::PerRuntimeFutexAPI::ErrorTooLong: + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ATOMICS_TOO_LONG); + retval = false; + break; + default: + MOZ_CRASH(); } if (w.lower_pri == &w) { diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index d2fc5aff7792..176903797b06 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -191,7 +191,7 @@ ParseEvalStringAsJSON(JSContext *cx, const mozilla::Range chars, Mu } static EvalJSONResult -TryEvalJSON(JSContext *cx, JSFlatString *str, MutableHandleValue rval) +TryEvalJSON(JSContext *cx, JSLinearString *str, MutableHandleValue rval) { if (str->hasLatin1Chars()) { AutoCheckCannotGC nogc; @@ -203,13 +203,13 @@ TryEvalJSON(JSContext *cx, JSFlatString *str, MutableHandleValue rval) return EvalJSON_NotJSON; } - AutoStableStringChars flatChars(cx); - if (!flatChars.init(cx, str)) + AutoStableStringChars linearChars(cx); + if (!linearChars.init(cx, str)) return EvalJSON_Failure; - return flatChars.isLatin1() - ? ParseEvalStringAsJSON(cx, flatChars.latin1Range(), rval) - : ParseEvalStringAsJSON(cx, flatChars.twoByteRange(), rval); + return linearChars.isLatin1() + ? ParseEvalStringAsJSON(cx, linearChars.latin1Range(), rval) + : ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval); } // Define subset of ExecuteType so that casting performs the injection. @@ -277,19 +277,19 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame thisv = ObjectValue(*thisobj); } - Rooted flatStr(cx, str->ensureFlat(cx)); - if (!flatStr) + RootedLinearString linearStr(cx, str->ensureLinear(cx)); + if (!linearStr) return false; RootedScript callerScript(cx, caller ? caller.script() : nullptr); - EvalJSONResult ejr = TryEvalJSON(cx, flatStr, args.rval()); + EvalJSONResult ejr = TryEvalJSON(cx, linearStr, args.rval()); if (ejr != EvalJSON_NotJSON) return ejr == EvalJSON_Success; EvalScriptGuard esg(cx); if (evalType == DIRECT_EVAL && caller.isNonEvalFunctionFrame()) - esg.lookupInEvalCache(flatStr, callerScript, pc); + esg.lookupInEvalCache(linearStr, callerScript, pc); if (!esg.foundScript()) { RootedScript maybeScript(cx); @@ -323,18 +323,18 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset) .maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc)); - AutoStableStringChars flatChars(cx); - if (!flatChars.initTwoByte(cx, flatStr)) + AutoStableStringChars linearChars(cx); + if (!linearChars.initTwoByte(cx, linearStr)) return false; - const char16_t *chars = flatChars.twoByteRange().start().get(); - SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller() + const char16_t *chars = linearChars.twoByteRange().start().get(); + SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; - SourceBufferHolder srcBuf(chars, flatStr->length(), ownership); + SourceBufferHolder srcBuf(chars, linearStr->length(), ownership); JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), scopeobj, callerScript, staticScope, - options, srcBuf, flatStr, staticLevel); + options, srcBuf, linearStr, staticLevel); if (!compiled) return false; @@ -366,17 +366,17 @@ js::DirectEvalStringFromIon(JSContext *cx, unsigned staticLevel = callerScript->staticLevel() + 1; - Rooted flatStr(cx, str->ensureFlat(cx)); - if (!flatStr) + RootedLinearString linearStr(cx, str->ensureLinear(cx)); + if (!linearStr) return false; - EvalJSONResult ejr = TryEvalJSON(cx, flatStr, vp); + EvalJSONResult ejr = TryEvalJSON(cx, linearStr, vp); if (ejr != EvalJSON_NotJSON) return ejr == EvalJSON_Success; EvalScriptGuard esg(cx); - esg.lookupInEvalCache(flatStr, callerScript, pc); + esg.lookupInEvalCache(linearStr, callerScript, pc); if (!esg.foundScript()) { RootedScript maybeScript(cx); @@ -405,18 +405,18 @@ js::DirectEvalStringFromIon(JSContext *cx, .setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset) .maybeMakeStrictMode(IsStrictEvalPC(pc)); - AutoStableStringChars flatChars(cx); - if (!flatChars.initTwoByte(cx, flatStr)) + AutoStableStringChars linearChars(cx); + if (!linearChars.initTwoByte(cx, linearStr)) return false; - const char16_t *chars = flatChars.twoByteRange().start().get(); - SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller() + const char16_t *chars = linearChars.twoByteRange().start().get(); + SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller() ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; - SourceBufferHolder srcBuf(chars, flatStr->length(), ownership); + SourceBufferHolder srcBuf(chars, linearStr->length(), ownership); JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), scopeobj, callerScript, staticScope, - options, srcBuf, flatStr, staticLevel); + options, srcBuf, linearStr, staticLevel); if (!compiled) return false; diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 9c2a5c82c50e..485533649d3b 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1226,6 +1226,11 @@ MapObject::construct(JSContext *cx, unsigned argc, Value *vp) return false; CallArgs args = CallArgsFromVp(argc, vp); + + // FIXME: bug 1083752 + if (!WarnIfNotConstructing(cx, args, "Map")) + return false; + if (!args.get(0).isNullOrUndefined()) { RootedValue adderVal(cx); if (!GetProperty(cx, obj, obj, cx->names().set, &adderVal)) @@ -1870,6 +1875,11 @@ SetObject::construct(JSContext *cx, unsigned argc, Value *vp) return false; CallArgs args = CallArgsFromVp(argc, vp); + + // FIXME: bug 1083752 + if (!WarnIfNotConstructing(cx, args, "Set")) + return false; + if (!args.get(0).isNullOrUndefined()) { RootedValue adderVal(cx); if (!GetProperty(cx, obj, obj, cx->names().add, &adderVal)) diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index 0bb2f4383a9c..4f91ae6b4d3b 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -97,16 +97,16 @@ function markGCType(typeName, child, why, depth, ptrdness) if (depth == 0) { if (!(typeName in gcTypes)) - gcTypes[typeName] = Set(); + gcTypes[typeName] = new Set(); gcTypes[typeName].add(why); } else if (depth == 1) { if (!(typeName in gcPointers)) - gcPointers[typeName] = Set(); + gcPointers[typeName] = new Set(); gcPointers[typeName].add(why); } if (!(typeName in gcFields)) - gcFields[typeName] = Map(); + gcFields[typeName] = new Map(); gcFields[typeName].set(why, [ child, ptrdness ]); if (typeName in structureParents) { @@ -148,7 +148,7 @@ addGCPointer('JS::AutoCheckCannotGC'); function explain(csu, indent, seen) { if (!seen) - seen = Set(); + seen = new Set(); seen.add(csu); if (!(csu in gcFields)) return; diff --git a/js/src/jit-test/lib/census.js b/js/src/jit-test/lib/census.js index cf250d70090d..966746cc9b1e 100644 --- a/js/src/jit-test/lib/census.js +++ b/js/src/jit-test/lib/census.js @@ -82,7 +82,7 @@ const Census = {}; function makeBasisChecker({compare, missing, extra}) { return function makeWalker(basis) { if (typeof basis === 'object') { - var unvisited = Set(Object.getOwnPropertyNames(basis)); + var unvisited = new Set(Object.getOwnPropertyNames(basis)); return { enter: prop => { unvisited.delete(prop); diff --git a/js/src/jit-test/tests/auto-regress/bug771027.js b/js/src/jit-test/tests/auto-regress/bug771027.js index 2d31514fb417..8c7b9a81a7e6 100644 --- a/js/src/jit-test/tests/auto-regress/bug771027.js +++ b/js/src/jit-test/tests/auto-regress/bug771027.js @@ -5,4 +5,5 @@ // Array.prototype.iterator = (function() { { while(0) function Uint8ClampedArray() { } } }); -assertEq(Set(["testing", "testing", 123]).size(), 2); +var s = new Set(["testing", "testing", 123]); +assertEq(s.size(), 2); diff --git a/js/src/jit-test/tests/basic/bug797496.js b/js/src/jit-test/tests/basic/bug797496.js index e33f3dbd9ebf..d8bc1897c543 100644 --- a/js/src/jit-test/tests/basic/bug797496.js +++ b/js/src/jit-test/tests/basic/bug797496.js @@ -1,8 +1,8 @@ // |jit-test| error: TypeError -var set = Set(['a']); +var set = new Set(['a']); var n = 5; for (let v of set) { if (n === 0) break; - let g = set(Set(0xffffffff, n), 1); + let g = set(new Set(0xffffffff, n), 1); } diff --git a/js/src/jit-test/tests/basic/bug808483.js b/js/src/jit-test/tests/basic/bug808483.js index 372485c8d9cd..9dd2be029386 100644 --- a/js/src/jit-test/tests/basic/bug808483.js +++ b/js/src/jit-test/tests/basic/bug808483.js @@ -1,7 +1,7 @@ pSandbox = newGlobal(); evalcx("\ x = ArrayBuffer;\ - y = Map();\ + y = new Map();\ x += 1;\ w = x;\ x += '0';\ diff --git a/js/src/jit-test/tests/basic/spread-array.js b/js/src/jit-test/tests/basic/spread-array.js index be4318402f79..30d4cb52b46c 100644 --- a/js/src/jit-test/tests/basic/spread-array.js +++ b/js/src/jit-test/tests/basic/spread-array.js @@ -19,8 +19,8 @@ assertEqArray([...[undefined]], [undefined]); assertEqArray([...new Int32Array([1, 2, 3])], [1, 2, 3]); assertEqArray([..."abc"], ["a", "b", "c"]); assertEqArray([...[1, 2, 3][Symbol.iterator]()], [1, 2, 3]); -assertEqArray([...Set([1, 2, 3])], [1, 2, 3]); -assertEqArray([...Map([["a", "A"], ["b", "B"], ["c", "C"]])].map(([k, v]) => k + v), ["aA", "bB", "cC"]); +assertEqArray([...new Set([1, 2, 3])], [1, 2, 3]); +assertEqArray([...new Map([["a", "A"], ["b", "B"], ["c", "C"]])].map(([k, v]) => k + v), ["aA", "bB", "cC"]); let itr = {}; itr[Symbol.iterator] = function () { return { diff --git a/js/src/jit-test/tests/basic/spread-call-eval.js b/js/src/jit-test/tests/basic/spread-call-eval.js index 290fcf3196cb..1fad8e7a591a 100644 --- a/js/src/jit-test/tests/basic/spread-call-eval.js +++ b/js/src/jit-test/tests/basic/spread-call-eval.js @@ -25,7 +25,7 @@ try { // line0 + 1 // other iterable objects assertEq(eval(...["a + b"][Symbol.iterator]()), 11); -assertEq(eval(...Set(["a + b"])), 11); +assertEq(eval(...new Set(["a + b"])), 11); let itr = {}; itr[Symbol.iterator] = function() { return { diff --git a/js/src/jit-test/tests/basic/spread-call-funapply.js b/js/src/jit-test/tests/basic/spread-call-funapply.js index e7a6cc54688b..9362d2a2d615 100644 --- a/js/src/jit-test/tests/basic/spread-call-funapply.js +++ b/js/src/jit-test/tests/basic/spread-call-funapply.js @@ -9,7 +9,7 @@ function checkCommon(f) { assertEqArray(f.apply(...[null, [1, 2, 3]]), [1, 2, 3]); // other iterable objects - assertEqArray(f.apply(...Set([null, [1, 2, 3]])), [1, 2, 3]); + assertEqArray(f.apply(...new Set([null, [1, 2, 3]])), [1, 2, 3]); assertEqArray(f.apply(...[null, [1, 2, 3]][Symbol.iterator]()), [1, 2, 3]); let itr = {}; itr[Symbol.iterator] = function() { @@ -81,7 +81,7 @@ function checkRest(f) { assertEqArray(f.apply(null, ...[[undefined]]), [undefined]); // other iterable objects - assertEqArray(f.apply(null, ...Map([[["a", "A"], ["b", "B"]]])).map(([k, v]) => k + v), ["aA", "bB"]); + assertEqArray(f.apply(null, ...new Map([[["a", "A"], ["b", "B"]]])).map(([k, v]) => k + v), ["aA", "bB"]); } checkRest(function(...x) x); diff --git a/js/src/jit-test/tests/basic/spread-call-length.js b/js/src/jit-test/tests/basic/spread-call-length.js index b4d6936a4b90..937eea780058 100644 --- a/js/src/jit-test/tests/basic/spread-call-length.js +++ b/js/src/jit-test/tests/basic/spread-call-length.js @@ -22,8 +22,8 @@ function checkLength(f, makeFn) { assertEq(makeFn("...arg")(f, new Int32Array([1, 2, 3])), 3); assertEq(makeFn("...arg")(f, "abc"), 3); assertEq(makeFn("...arg")(f, [1, 2, 3][Symbol.iterator]()), 3); - assertEq(makeFn("...arg")(f, Set([1, 2, 3])), 3); - assertEq(makeFn("...arg")(f, Map([["a", "A"], ["b", "B"], ["c", "C"]])), 3); + assertEq(makeFn("...arg")(f, new Set([1, 2, 3])), 3); + assertEq(makeFn("...arg")(f, new Map([["a", "A"], ["b", "B"], ["c", "C"]])), 3); let itr = {}; itr[Symbol.iterator] = function() { return { diff --git a/js/src/jit-test/tests/basic/spread-call.js b/js/src/jit-test/tests/basic/spread-call.js index d36e9cf201fa..927c6d0f412f 100644 --- a/js/src/jit-test/tests/basic/spread-call.js +++ b/js/src/jit-test/tests/basic/spread-call.js @@ -17,8 +17,8 @@ function checkCommon(f, makeFn) { assertEqArray(makeFn("...arg")(f, new Int32Array([1, 2, 3])), [1, 2, 3]); assertEqArray(makeFn("...arg")(f, "abc"), ["a", "b", "c"]); assertEqArray(makeFn("...arg")(f, [1, 2, 3][Symbol.iterator]()), [1, 2, 3]); - assertEqArray(makeFn("...arg")(f, Set([1, 2, 3])), [1, 2, 3]); - assertEqArray(makeFn("...arg")(f, Map([["a", "A"], ["b", "B"], ["c", "C"]])).map(([k, v]) => k + v), ["aA", "bB", "cC"]); + assertEqArray(makeFn("...arg")(f, new Set([1, 2, 3])), [1, 2, 3]); + assertEqArray(makeFn("...arg")(f, new Map([["a", "A"], ["b", "B"], ["c", "C"]])).map(([k, v]) => k + v), ["aA", "bB", "cC"]); let itr = {}; itr[Symbol.iterator] = function() { return { diff --git a/js/src/jit-test/tests/collections/Map-clear-1.js b/js/src/jit-test/tests/collections/Map-clear-1.js index 0684c400eea8..68b08cdb2282 100644 --- a/js/src/jit-test/tests/collections/Map-clear-1.js +++ b/js/src/jit-test/tests/collections/Map-clear-1.js @@ -1,6 +1,6 @@ // Clearing an empty Map has no effect. -var m = Map(); +var m = new Map(); for (var i = 0; i < 2; i++) { m.clear(); assertEq(m.size, 0); diff --git a/js/src/jit-test/tests/collections/Map-clear-2.js b/js/src/jit-test/tests/collections/Map-clear-2.js index 27fa4cd5ea89..f9358b6f0c57 100644 --- a/js/src/jit-test/tests/collections/Map-clear-2.js +++ b/js/src/jit-test/tests/collections/Map-clear-2.js @@ -1,6 +1,6 @@ // Clearing a Map removes its entries; the Map remains usable afterwards. -var m = Map([["a", "b"], ["b", "c"]]); +var m = new Map([["a", "b"], ["b", "c"]]); assertEq(m.size, 2); m.clear(); assertEq(m.size, 0); diff --git a/js/src/jit-test/tests/collections/Map-clear-3.js b/js/src/jit-test/tests/collections/Map-clear-3.js index 6666479d930e..902a4cf292e3 100644 --- a/js/src/jit-test/tests/collections/Map-clear-3.js +++ b/js/src/jit-test/tests/collections/Map-clear-3.js @@ -1,6 +1,6 @@ // Clearing a Map with a nontrivial number of elements works. -var m = Map(); +var m = new Map(); for (var i = 0; i < 100; i++) m.set(i, i); assertEq(m.size, i); diff --git a/js/src/jit-test/tests/collections/Map-clear-4.js b/js/src/jit-test/tests/collections/Map-clear-4.js index 6e9fc12da0d5..2925c801f883 100644 --- a/js/src/jit-test/tests/collections/Map-clear-4.js +++ b/js/src/jit-test/tests/collections/Map-clear-4.js @@ -1,6 +1,6 @@ // Clearing a Map after deleting some entries works. -var m = Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]); +var m = new Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]); for (var [k, v] of m) if (k !== "c") m.delete(k); diff --git a/js/src/jit-test/tests/collections/Map-clear-5.js b/js/src/jit-test/tests/collections/Map-clear-5.js index 264365e48076..74fcdd4ebe46 100644 --- a/js/src/jit-test/tests/collections/Map-clear-5.js +++ b/js/src/jit-test/tests/collections/Map-clear-5.js @@ -1,7 +1,7 @@ // Map.clear is unaffected by deleting/monkeypatching Map.prototype.{delete,iterator}. var data = [["a", 1], ["b", 2]]; -var m1 = Map(data), m2 = Map(data); +var m1 = new Map(data), m2 = new Map(data); delete Map.prototype.delete; delete Map.prototype.iterator; diff --git a/js/src/jit-test/tests/collections/Map-clear-6.js b/js/src/jit-test/tests/collections/Map-clear-6.js index fcb4690064e6..4df7388f59fd 100644 --- a/js/src/jit-test/tests/collections/Map-clear-6.js +++ b/js/src/jit-test/tests/collections/Map-clear-6.js @@ -1,6 +1,6 @@ // Clearing a Map doesn't affect expando properties. -var m = Map(); +var m = new Map(); m.x = 3; m.clear(); assertEq(m.x, 3); diff --git a/js/src/jit-test/tests/collections/Map-clear-gc.js b/js/src/jit-test/tests/collections/Map-clear-gc.js index 56b72bfd4335..ae624e63a4ee 100644 --- a/js/src/jit-test/tests/collections/Map-clear-gc.js +++ b/js/src/jit-test/tests/collections/Map-clear-gc.js @@ -2,7 +2,7 @@ load(libdir + "referencesVia.js"); -var m = Map(); +var m = new Map(); var k = {}, v = {}; m.set(k, v); assertEq(referencesVia(m, "key", k), true); diff --git a/js/src/jit-test/tests/collections/Map-clear-iterators-1.js b/js/src/jit-test/tests/collections/Map-clear-iterators-1.js index d1a182f242e6..0372929fb938 100644 --- a/js/src/jit-test/tests/collections/Map-clear-iterators-1.js +++ b/js/src/jit-test/tests/collections/Map-clear-iterators-1.js @@ -2,19 +2,19 @@ load(libdir + "iteration.js"); -var m = Map(); +var m = new Map(); var it = m[Symbol.iterator](); m.clear(); assertIteratorDone(it, undefined); -m = Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]); +m = new Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]); it = m[Symbol.iterator](); assertIteratorNext(it, ["a", 1]); m.clear(); assertIteratorDone(it, undefined); var log = ""; -m = Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]); +m = new Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]); for (var [k, v] of m) { log += k + v; if (k == "b") diff --git a/js/src/jit-test/tests/collections/Map-clear-iterators-2.js b/js/src/jit-test/tests/collections/Map-clear-iterators-2.js index ad299a58948f..a64b5f11cb7d 100644 --- a/js/src/jit-test/tests/collections/Map-clear-iterators-2.js +++ b/js/src/jit-test/tests/collections/Map-clear-iterators-2.js @@ -3,7 +3,7 @@ load(libdir + "asserts.js"); load(libdir + "iteration.js"); -var m = Map([["a", 1]]); +var m = new Map([["a", 1]]); var it = m[Symbol.iterator](); assertIteratorNext(it, ["a", 1]); m.clear(); diff --git a/js/src/jit-test/tests/collections/Map-constructor-1.js b/js/src/jit-test/tests/collections/Map-constructor-1.js index 47d37796f971..44a6be9ee3f8 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-1.js +++ b/js/src/jit-test/tests/collections/Map-constructor-1.js @@ -1,7 +1,17 @@ // The Map constructor creates an empty Map by default. -assertEq(Map().size, 0); -assertEq((new Map).size, 0); -assertEq(Map(undefined).size, 0); -assertEq(new Map(undefined).size, 0); -assertEq(new Map(null).size, 0); +load(libdir + "asserts.js"); + +var m = new Map(); +assertEq(m.size, 0); +m = new Map(undefined); +assertEq(m.size, 0); +m = new Map(null); +assertEq(m.size, 0); + +// FIXME: bug 1083752 +options("werror"); +assertEq(evaluate("Map()", {catchTermination: true}), "terminated"); +// assertThrowsInstanceOf(() => Map(), TypeError); +// assertThrowsInstanceOf(() => Map(undefined), TypeError); +// assertThrowsInstanceOf(() => Map(null), TypeError); diff --git a/js/src/jit-test/tests/collections/Map-constructor-2.js b/js/src/jit-test/tests/collections/Map-constructor-2.js index 91c0fd5afd0d..b80a171d846a 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-2.js +++ b/js/src/jit-test/tests/collections/Map-constructor-2.js @@ -1,6 +1,6 @@ // The Map constructor can take an argument that is an array of pairs. var arr = [["zero", 0], ["one", 1], ["two", 2]]; -var m = Map(arr); +var m = new Map(arr); for (var [k, v] of arr) assertEq(m.get(k), v); diff --git a/js/src/jit-test/tests/collections/Map-constructor-3.js b/js/src/jit-test/tests/collections/Map-constructor-3.js index bb388b3a33a8..601a76188ebc 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-3.js +++ b/js/src/jit-test/tests/collections/Map-constructor-3.js @@ -1,7 +1,7 @@ // Map can take an argument that is an array of singleton arrays. var arr = [["a"], ["b"], ["c"]]; -var m = Map(arr); +var m = new Map(arr); assertEq(m.size, 3); for (var [k, _] of arr) { assertEq(m.has(k), true); diff --git a/js/src/jit-test/tests/collections/Map-constructor-4.js b/js/src/jit-test/tests/collections/Map-constructor-4.js index c02458d59a8e..22c2c416be4b 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-4.js +++ b/js/src/jit-test/tests/collections/Map-constructor-4.js @@ -1,6 +1,6 @@ -// Map(x) throws if x is not iterable (unless x is undefined). +// new Map(x) throws if x is not iterable (unless x is undefined). load(libdir + "asserts.js"); var nonIterables = [true, 1, -0, 3.14, NaN, {}, Math, this]; for (let k of nonIterables) - assertThrowsInstanceOf(function () { Map(k); }, TypeError); + assertThrowsInstanceOf(function () { new Map(k); }, TypeError); diff --git a/js/src/jit-test/tests/collections/Map-constructor-5.js b/js/src/jit-test/tests/collections/Map-constructor-5.js index 59df26ae6732..98d1a03ba459 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-5.js +++ b/js/src/jit-test/tests/collections/Map-constructor-5.js @@ -1,14 +1,14 @@ -// Map(arr) throws if arr contains holes (or undefined values). +// new Map(arr) throws if arr contains holes (or undefined values). load(libdir + "asserts.js"); -assertThrowsInstanceOf(function () { Map([undefined]); }, TypeError); -assertThrowsInstanceOf(function () { Map([null]); }, TypeError); -assertThrowsInstanceOf(function () { Map([[0, 0], [1, 1], , [3, 3]]); }, TypeError); -assertThrowsInstanceOf(function () { Map([[0, 0], [1, 1], ,]); }, TypeError); +assertThrowsInstanceOf(function () { new Map([undefined]); }, TypeError); +assertThrowsInstanceOf(function () { new Map([null]); }, TypeError); +assertThrowsInstanceOf(function () { new Map([[0, 0], [1, 1], , [3, 3]]); }, TypeError); +assertThrowsInstanceOf(function () { new Map([[0, 0], [1, 1], ,]); }, TypeError); -// Map(iterable) throws if iterable doesn't have array-like objects +// new Map(iterable) throws if iterable doesn't have array-like objects -assertThrowsInstanceOf(function () { Map([1, 2, 3]); }, TypeError); +assertThrowsInstanceOf(function () { new Map([1, 2, 3]); }, TypeError); assertThrowsInstanceOf(function () { let s = new Set([1, 2, "abc"]); new Map(s); diff --git a/js/src/jit-test/tests/collections/Map-constructor-duplicates.js b/js/src/jit-test/tests/collections/Map-constructor-duplicates.js index 3be687471219..125081bf8764 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-duplicates.js +++ b/js/src/jit-test/tests/collections/Map-constructor-duplicates.js @@ -1,7 +1,7 @@ // When the argument to Map contains a key multiple times, the last value is retained. var arg = [["zero", 7], ["one", 1], ["two", 4], ["zero", 8], ["two", 2], ["zero", 0]]; -var m = Map(arg); +var m = new Map(arg); assertEq(m.get("zero"), 0); assertEq(m.get("one"), 1); assertEq(m.get("two"), 2); diff --git a/js/src/jit-test/tests/collections/Map-constructor-generator-1.js b/js/src/jit-test/tests/collections/Map-constructor-generator-1.js index 3278f6704dde..61a319846cc1 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-generator-1.js +++ b/js/src/jit-test/tests/collections/Map-constructor-generator-1.js @@ -10,7 +10,7 @@ function data(n) { done = true; } -var m = Map(data(50)); +var m = new Map(data(50)); assertEq(done, true); // the constructor consumes the argument assertEq(m.size, 50); assertEq(m.get(""), 0); diff --git a/js/src/jit-test/tests/collections/Map-constructor-generator-2.js b/js/src/jit-test/tests/collections/Map-constructor-generator-2.js index d2bf399ba7b9..bcf2a85d31e5 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-generator-2.js +++ b/js/src/jit-test/tests/collections/Map-constructor-generator-2.js @@ -1,7 +1,7 @@ // The argument to Map can be a generator-expression. var arr = [1, 2, "green", "red"]; -var m = Map([v, v] for (v of arr)); +var m = new Map([v, v] for (v of arr)); assertEq(m.size, 4); for (var i = 0; i < 4; i++) diff --git a/js/src/jit-test/tests/collections/Map-constructor-generator-3.js b/js/src/jit-test/tests/collections/Map-constructor-generator-3.js index cddcbb5d43cc..4c2de0428e43 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-generator-3.js +++ b/js/src/jit-test/tests/collections/Map-constructor-generator-3.js @@ -1,8 +1,10 @@ // The argument to Map may be a generator-iterator that produces no values. -assertEq(Map(x for (x of [])).size, 0); +var m = new Map(x for (x of [])); +assertEq(m.size, 0); function none() { if (0) yield 0; } -assertEq(Map(none()).size, 0); +m = new Map(none()); +assertEq(m.size, 0); diff --git a/js/src/jit-test/tests/collections/Map-constructor-generator-exception.js b/js/src/jit-test/tests/collections/Map-constructor-generator-exception.js index 3bd553888316..c3ec3c1c7280 100644 --- a/js/src/jit-test/tests/collections/Map-constructor-generator-exception.js +++ b/js/src/jit-test/tests/collections/Map-constructor-generator-exception.js @@ -9,4 +9,4 @@ function data2() { } var it = data2(); -assertThrowsValue(function () { Map(it); }, "oops"); +assertThrowsValue(function () { new Map(it); }, "oops"); diff --git a/js/src/jit-test/tests/collections/Map-delete-size.js b/js/src/jit-test/tests/collections/Map-delete-size.js index 44189f89ea1c..c2537e0dc1e4 100644 --- a/js/src/jit-test/tests/collections/Map-delete-size.js +++ b/js/src/jit-test/tests/collections/Map-delete-size.js @@ -1,6 +1,6 @@ // map.delete(k) decrements the map size iff an entry was actually removed. -var m = Map(); +var m = new Map(); m.delete(3); assertEq(m.size, 0); m.set({}, 'ok'); diff --git a/js/src/jit-test/tests/collections/Map-iterator-1.js b/js/src/jit-test/tests/collections/Map-iterator-1.js index 3239efa55c75..5e9d685737af 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-1.js +++ b/js/src/jit-test/tests/collections/Map-iterator-1.js @@ -1,6 +1,6 @@ // for-of can be used to iterate over a Map twice. -var map = Map([['a', 0], ['b', 1], ['c', 2]]); +var map = new Map([['a', 0], ['b', 1], ['c', 2]]); var log = ''; for (let i = 0; i < 2; i++) { diff --git a/js/src/jit-test/tests/collections/Map-iterator-2.js b/js/src/jit-test/tests/collections/Map-iterator-2.js index 1634a56531da..8a648a273a43 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-2.js +++ b/js/src/jit-test/tests/collections/Map-iterator-2.js @@ -1,6 +1,6 @@ // Nested for-of loops can iterate over a Map. -var map = Map([['a', 0], ['b', 1]]); +var map = new Map([['a', 0], ['b', 1]]); var log = ''; for (let [k0, v0] of map) { log += k0 + v0 + ':' diff --git a/js/src/jit-test/tests/collections/Map-iterator-add-1.js b/js/src/jit-test/tests/collections/Map-iterator-add-1.js index 01d20822c9cb..495ad6288203 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-add-1.js +++ b/js/src/jit-test/tests/collections/Map-iterator-add-1.js @@ -1,6 +1,6 @@ // map.iterator() is live: entries added during iteration are visited. -var map = Map(); +var map = new Map(); function force(k) { if (!map.has(k) && k >= 0) map.set(k, k - 1); diff --git a/js/src/jit-test/tests/collections/Map-iterator-add-2.js b/js/src/jit-test/tests/collections/Map-iterator-add-2.js index 3b1ea08e2bda..fce3dac6ed0c 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-add-2.js +++ b/js/src/jit-test/tests/collections/Map-iterator-add-2.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var map = Map(); +var map = new Map(); var iter0 = map[Symbol.iterator](), iter1 = map[Symbol.iterator](); assertIteratorDone(iter0, undefined); // closes iter0 map.set(1, 2); diff --git a/js/src/jit-test/tests/collections/Map-iterator-add-remove.js b/js/src/jit-test/tests/collections/Map-iterator-add-remove.js index e44a2b503831..b71bfd18cf60 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-add-remove.js +++ b/js/src/jit-test/tests/collections/Map-iterator-add-remove.js @@ -1,6 +1,6 @@ // Removing and re-adding entries while an iterator is live causes the iterator to visit them again. -var map = Map([['a', 1]]); +var map = new Map([['a', 1]]); var n = 5; for (let [k, v] of map) { assertEq(k, 'a'); diff --git a/js/src/jit-test/tests/collections/Map-iterator-order.js b/js/src/jit-test/tests/collections/Map-iterator-order.js index 72161886c591..55eb30360d84 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-order.js +++ b/js/src/jit-test/tests/collections/Map-iterator-order.js @@ -2,7 +2,7 @@ load(libdir + "eqArrayHelper.js"); -var map = Map(); +var map = new Map(); for (var i = 7; i !== 1; i = i * 7 % 1117) map.set("" + i, i); assertEq(map.size, 557); diff --git a/js/src/jit-test/tests/collections/Map-iterator-pairs-1.js b/js/src/jit-test/tests/collections/Map-iterator-pairs-1.js index 635a44ad803b..2a8e49d89b34 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-pairs-1.js +++ b/js/src/jit-test/tests/collections/Map-iterator-pairs-1.js @@ -3,7 +3,7 @@ load(libdir + "iteration.js"); var key = {}; -var map = Map([[key, 'value']]); +var map = new Map([[key, 'value']]); var entry = map[Symbol.iterator]().next().value; assertEq(Array.isArray(entry), true); assertEq(Object.getPrototypeOf(entry), Array.prototype); diff --git a/js/src/jit-test/tests/collections/Map-iterator-pairs-2.js b/js/src/jit-test/tests/collections/Map-iterator-pairs-2.js index c761da37e173..4d4e66f00c49 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-pairs-2.js +++ b/js/src/jit-test/tests/collections/Map-iterator-pairs-2.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var map = Map([['a', 1], ['b', 2]]); +var map = new Map([['a', 1], ['b', 2]]); var iter = map[Symbol.iterator](); var a = iter.next(), b = iter.next(); assertIteratorResult(a, ['a', 1], false); diff --git a/js/src/jit-test/tests/collections/Map-iterator-pairs-3.js b/js/src/jit-test/tests/collections/Map-iterator-pairs-3.js index f40146a72fa1..738215b791c7 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-pairs-3.js +++ b/js/src/jit-test/tests/collections/Map-iterator-pairs-3.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var map = Map([['a', 1]]); +var map = new Map([['a', 1]]); var res = map[Symbol.iterator]().next(); assertIteratorResult(res, ['a', 1], false); res.value[0] = 'b'; diff --git a/js/src/jit-test/tests/collections/Map-iterator-proxies-1.js b/js/src/jit-test/tests/collections/Map-iterator-proxies-1.js index 4a6e5c1290b8..545d80b6ac0a 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-proxies-1.js +++ b/js/src/jit-test/tests/collections/Map-iterator-proxies-1.js @@ -1,7 +1,7 @@ // for-of works on a cross-compartment wrapper of a Map. var g = newGlobal(); -var mw = g.eval("Map([['a', 1], ['b', 2]])"); +var mw = g.eval("new Map([['a', 1], ['b', 2]])"); var log = ''; for (let [k, v] of mw) log += k + v; diff --git a/js/src/jit-test/tests/collections/Map-iterator-proxies-2.js b/js/src/jit-test/tests/collections/Map-iterator-proxies-2.js index 057f0ab77625..9b1c8bb9852f 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-proxies-2.js +++ b/js/src/jit-test/tests/collections/Map-iterator-proxies-2.js @@ -8,13 +8,13 @@ var g = newGlobal(); var iterator_fn = Map.prototype[Symbol.iterator]; assertThrowsInstanceOf(function () { iterator_fn.call({}); }, TypeError); -assertThrowsInstanceOf(function () { iterator_fn.call(Set()); }, TypeError); -var mapw = g.eval("Map([['x', 1], ['y', 2]])"); +assertThrowsInstanceOf(function () { iterator_fn.call(new Set()); }, TypeError); +var mapw = g.eval("new Map([['x', 1], ['y', 2]])"); assertEqArray(iterator_fn.call(mapw).next().value, ["x", 1]); -var next_fn = Map()[Symbol.iterator]().next; +var next_fn = (new Map())[Symbol.iterator]().next; assertThrowsInstanceOf(function () { next_fn.call({}); }, TypeError); -assertThrowsInstanceOf(function () { next_fn.call(Set()[Symbol.iterator]()); }, TypeError); +assertThrowsInstanceOf(function () { next_fn.call((new Set())[Symbol.iterator]()); }, TypeError); var iterw = mapw[Symbol.iterator](); assertEqArray(next_fn.call(iterw).value, ["x", 1]); assertEqArray(next_fn.call(iterw).value, ["y", 2]); diff --git a/js/src/jit-test/tests/collections/Map-iterator-remove-1.js b/js/src/jit-test/tests/collections/Map-iterator-remove-1.js index d4e1a6dfcb43..43b15d193965 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-remove-1.js +++ b/js/src/jit-test/tests/collections/Map-iterator-remove-1.js @@ -2,7 +2,7 @@ function test(pairs) { print(uneval(pairs)); - var map = Map(pairs); + var map = new Map(pairs); var all_keys = ''; var false_keys = ''; diff --git a/js/src/jit-test/tests/collections/Map-iterator-remove-2.js b/js/src/jit-test/tests/collections/Map-iterator-remove-2.js index 0e9f589752d6..d49efa1c88a9 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-remove-2.js +++ b/js/src/jit-test/tests/collections/Map-iterator-remove-2.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var map = Map([['a', 0], ['b', 1], ['c', 2], ['d', 3]]); +var map = new Map([['a', 0], ['b', 1], ['c', 2], ['d', 3]]); var iter = map[Symbol.iterator](); var log = ''; for (let [k, v] of iter) { diff --git a/js/src/jit-test/tests/collections/Map-iterator-remove-3.js b/js/src/jit-test/tests/collections/Map-iterator-remove-3.js index 1506dcc569f1..0b17dcfec8e0 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-remove-3.js +++ b/js/src/jit-test/tests/collections/Map-iterator-remove-3.js @@ -3,7 +3,7 @@ load(libdir + "asserts.js"); load(libdir + "iteration.js"); -var map = Map([['a', 0], ['b', 1], ['c', 2], ['d', 3]]); +var map = new Map([['a', 0], ['b', 1], ['c', 2], ['d', 3]]); var iter = map[Symbol.iterator](); assertIteratorNext(iter, ['a', 0]); assertIteratorNext(iter, ['b', 1]); diff --git a/js/src/jit-test/tests/collections/Map-iterator-remove-4.js b/js/src/jit-test/tests/collections/Map-iterator-remove-4.js index 405a8771d9cc..7739000137e5 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-remove-4.js +++ b/js/src/jit-test/tests/collections/Map-iterator-remove-4.js @@ -3,7 +3,7 @@ load(libdir + "iteration.js"); // Make a map. -var map = Map(); +var map = new Map(); var SIZE = 7; for (var j = 0; j < SIZE; j++) map.set(j, j); diff --git a/js/src/jit-test/tests/collections/Map-iterator-remove-5.js b/js/src/jit-test/tests/collections/Map-iterator-remove-5.js index c7e7d9ff096d..d5e3c26b2e68 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-remove-5.js +++ b/js/src/jit-test/tests/collections/Map-iterator-remove-5.js @@ -1,7 +1,7 @@ // Removing a Map entry already visited by an iterator does not cause any // entries to be skipped. -var map = Map(); +var map = new Map(); for (var i = 0; i < 20; i++) map.set(String.fromCharCode('A'.charCodeAt(0) + i), i); diff --git a/js/src/jit-test/tests/collections/Map-iterator-remove-6.js b/js/src/jit-test/tests/collections/Map-iterator-remove-6.js index 4b0fbc13b03a..9fc6f1e56ebe 100644 --- a/js/src/jit-test/tests/collections/Map-iterator-remove-6.js +++ b/js/src/jit-test/tests/collections/Map-iterator-remove-6.js @@ -4,7 +4,7 @@ load(libdir + "iteration.js"); -var map = Map(); +var map = new Map(); for (var i = 0; i < 32; i++) map.set(i, i); var iter = map[Symbol.iterator](); diff --git a/js/src/jit-test/tests/collections/Map-iterators-3.js b/js/src/jit-test/tests/collections/Map-iterators-3.js index e30d9be5980a..d1aac03f846d 100644 --- a/js/src/jit-test/tests/collections/Map-iterators-3.js +++ b/js/src/jit-test/tests/collections/Map-iterators-3.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var m = Map(); +var m = new Map(); var it = m[Symbol.iterator](); assertIteratorDone(it, undefined); // close the iterator m.clear(); diff --git a/js/src/jit-test/tests/collections/Map-set-size.js b/js/src/jit-test/tests/collections/Map-set-size.js index 10f967087cd2..3c4a13c85e96 100644 --- a/js/src/jit-test/tests/collections/Map-set-size.js +++ b/js/src/jit-test/tests/collections/Map-set-size.js @@ -1,6 +1,6 @@ // map.set(k, v) increments the map size iff map didn't already have an entry for k. -var m = Map(); +var m = new Map(); m.set('a', 0); assertEq(m.size, 1); m.set('a', 0); diff --git a/js/src/jit-test/tests/collections/Map-size.js b/js/src/jit-test/tests/collections/Map-size.js index ef5d786479a3..12cb6e7358ab 100644 --- a/js/src/jit-test/tests/collections/Map-size.js +++ b/js/src/jit-test/tests/collections/Map-size.js @@ -1,6 +1,6 @@ // Each Map has its own size. -var m1 = Map(), m2 = Map(); +var m1 = new Map(), m2 = new Map(); m1.set("x", 3); assertEq(m1.size, 1); assertEq(m2.size, 0); diff --git a/js/src/jit-test/tests/collections/Map-surfaces-1.js b/js/src/jit-test/tests/collections/Map-surfaces-1.js index f03d85f66628..2691f95e0d41 100644 --- a/js/src/jit-test/tests/collections/Map-surfaces-1.js +++ b/js/src/jit-test/tests/collections/Map-surfaces-1.js @@ -14,8 +14,7 @@ assertEq(Map.name, "Map"); assertEq(Object.getPrototypeOf(Map.prototype), Object.prototype); assertEq(Object.prototype.toString.call(Map.prototype), "[object Map]"); -assertEq(Object.prototype.toString.call(new Map), "[object Map]"); -assertEq(Object.prototype.toString.call(Map()), "[object Map]"); +assertEq(Object.prototype.toString.call(new Map()), "[object Map]"); assertEq(Object.keys(Map.prototype).join(), ""); assertEq(Map.prototype.constructor, Map); diff --git a/js/src/jit-test/tests/collections/Map-values-1.js b/js/src/jit-test/tests/collections/Map-values-1.js index 96c17445ff0d..8a31b590761e 100644 --- a/js/src/jit-test/tests/collections/Map-values-1.js +++ b/js/src/jit-test/tests/collections/Map-values-1.js @@ -1,6 +1,6 @@ // map.keys(), .values(), and .entries() on an empty map produce empty iterators. -var m = Map(); +var m = new Map(); var ki = m.keys(), vi = m.values(), ei = m.entries(); var p = Object.getPrototypeOf(ki) assertEq(Object.getPrototypeOf(vi), p); diff --git a/js/src/jit-test/tests/collections/Map-values-2.js b/js/src/jit-test/tests/collections/Map-values-2.js index cda60460a5c7..d6ca12b7f428 100644 --- a/js/src/jit-test/tests/collections/Map-values-2.js +++ b/js/src/jit-test/tests/collections/Map-values-2.js @@ -4,7 +4,7 @@ load(libdir + "iteration.js"); var data = [["one", 1], ["two", 2], ["three", 3], ["four", 4]]; -var m = Map(data); +var m = new Map(data); var ki = m.keys(); assertIteratorNext(ki, "one"); diff --git a/js/src/jit-test/tests/collections/Set-add-size.js b/js/src/jit-test/tests/collections/Set-add-size.js index ceb4bdbff926..dfd131db6765 100644 --- a/js/src/jit-test/tests/collections/Set-add-size.js +++ b/js/src/jit-test/tests/collections/Set-add-size.js @@ -1,6 +1,6 @@ // set.add(v) increments set.size iff the set did not already contain v. -var s = Set(); +var s = new Set(); for (var i = 0; i < 10; i++) { assertEq(s.size, i); s.add(i); diff --git a/js/src/jit-test/tests/collections/Set-clear-1.js b/js/src/jit-test/tests/collections/Set-clear-1.js index c866769bcc6d..ce6bc195261f 100644 --- a/js/src/jit-test/tests/collections/Set-clear-1.js +++ b/js/src/jit-test/tests/collections/Set-clear-1.js @@ -1,6 +1,6 @@ // Clearing an empty Set has no effect. -var s = Set(); +var s = new Set(); for (var i = 0; i < 2; i++) { s.clear(); assertEq(s.size, 0); diff --git a/js/src/jit-test/tests/collections/Set-clear-2.js b/js/src/jit-test/tests/collections/Set-clear-2.js index b711daa978e3..f3bbd77da071 100644 --- a/js/src/jit-test/tests/collections/Set-clear-2.js +++ b/js/src/jit-test/tests/collections/Set-clear-2.js @@ -1,6 +1,6 @@ // Clearing a Set removes its elements; the Set remains usable afterwards. -var s = Set(["x", "y", "z", "z", "y"]); +var s = new Set(["x", "y", "z", "z", "y"]); assertEq(s.size, 3); s.clear(); assertEq(s.size, 0); diff --git a/js/src/jit-test/tests/collections/Set-clear-3.js b/js/src/jit-test/tests/collections/Set-clear-3.js index 6c08b99cdc70..0fe138212ece 100644 --- a/js/src/jit-test/tests/collections/Set-clear-3.js +++ b/js/src/jit-test/tests/collections/Set-clear-3.js @@ -1,6 +1,6 @@ // Clearing a Set with a nontrivial number of elements works. -var s = Set(); +var s = new Set(); for (var i = 0; i < 100; i++) s.add(i); assertEq(s.size, i); diff --git a/js/src/jit-test/tests/collections/Set-clear-4.js b/js/src/jit-test/tests/collections/Set-clear-4.js index 8f6eb4aeda9a..5551a07abe2f 100644 --- a/js/src/jit-test/tests/collections/Set-clear-4.js +++ b/js/src/jit-test/tests/collections/Set-clear-4.js @@ -1,6 +1,6 @@ // Clearing a Set after deleting some entries works. -var s = Set(["a", "b", "c", "d"]); +var s = new Set(["a", "b", "c", "d"]); for (var v of s) if (v !== "c") s.delete(v); diff --git a/js/src/jit-test/tests/collections/Set-clear-5.js b/js/src/jit-test/tests/collections/Set-clear-5.js index 813b0d0fd707..48c5bf86882d 100644 --- a/js/src/jit-test/tests/collections/Set-clear-5.js +++ b/js/src/jit-test/tests/collections/Set-clear-5.js @@ -1,7 +1,7 @@ // Set.clear is unaffected by deleting/monkeypatching Set.prototype.{delete,iterator}. var data = ["a", 1, {}]; -var s1 = Set(data), s2 = Set(data); +var s1 = new Set(data), s2 = new Set(data); delete Set.prototype.delete; delete Set.prototype.iterator; diff --git a/js/src/jit-test/tests/collections/Set-clear-6.js b/js/src/jit-test/tests/collections/Set-clear-6.js index f2e2153d9bbc..5c8cfce00665 100644 --- a/js/src/jit-test/tests/collections/Set-clear-6.js +++ b/js/src/jit-test/tests/collections/Set-clear-6.js @@ -1,6 +1,6 @@ // Clearing a Set doesn't affect expando properties. -var s = Set(); +var s = new Set(); s.x = 3; s.clear(); assertEq(s.x, 3); diff --git a/js/src/jit-test/tests/collections/Set-clear-gc.js b/js/src/jit-test/tests/collections/Set-clear-gc.js index 84d92d75f356..739a0bd25504 100644 --- a/js/src/jit-test/tests/collections/Set-clear-gc.js +++ b/js/src/jit-test/tests/collections/Set-clear-gc.js @@ -2,7 +2,7 @@ load(libdir + "referencesVia.js"); -var s = Set(); +var s = new Set(); var obj = {}; s.add(obj); assertEq(referencesVia(s, "key", obj), true); diff --git a/js/src/jit-test/tests/collections/Set-clear-iterators-1.js b/js/src/jit-test/tests/collections/Set-clear-iterators-1.js index 0eec14053c9b..b5198ed64abd 100644 --- a/js/src/jit-test/tests/collections/Set-clear-iterators-1.js +++ b/js/src/jit-test/tests/collections/Set-clear-iterators-1.js @@ -2,19 +2,19 @@ load(libdir + "iteration.js"); -var s = Set(); +var s = new Set(); var it = s[Symbol.iterator](); s.clear(); assertIteratorDone(it, undefined); -s = Set(["a", "b", "c", "d"]); +s = new Set(["a", "b", "c", "d"]); it = s[Symbol.iterator](); assertIteratorNext(it, "a"); s.clear(); assertIteratorDone(it, undefined); var log = ""; -s = Set(["a", "b", "c", "d"]); +s = new Set(["a", "b", "c", "d"]); for (var v of s) { log += v; if (v == "b") diff --git a/js/src/jit-test/tests/collections/Set-clear-iterators-2.js b/js/src/jit-test/tests/collections/Set-clear-iterators-2.js index 77b8f72f706e..3b80d42c33a3 100644 --- a/js/src/jit-test/tests/collections/Set-clear-iterators-2.js +++ b/js/src/jit-test/tests/collections/Set-clear-iterators-2.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var s = Set(["a"]); +var s = new Set(["a"]); var it = s[Symbol.iterator](); assertIteratorNext(it, "a"); s.clear(); diff --git a/js/src/jit-test/tests/collections/Set-clear-iterators-3.js b/js/src/jit-test/tests/collections/Set-clear-iterators-3.js index 199ea67e71bb..c814d4ca9ae5 100644 --- a/js/src/jit-test/tests/collections/Set-clear-iterators-3.js +++ b/js/src/jit-test/tests/collections/Set-clear-iterators-3.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var s = Set(); +var s = new Set(); var it = s[Symbol.iterator](); assertIteratorDone(it, undefined); // close the iterator s.clear(); diff --git a/js/src/jit-test/tests/collections/Set-constructor-1.js b/js/src/jit-test/tests/collections/Set-constructor-1.js index 2b0cf17d3154..35a2dedb5e04 100644 --- a/js/src/jit-test/tests/collections/Set-constructor-1.js +++ b/js/src/jit-test/tests/collections/Set-constructor-1.js @@ -1,7 +1,17 @@ // The Set constructor creates an empty Set by default. -assertEq(Set().size, 0); -assertEq((new Set).size, 0); -assertEq(Set(undefined).size, 0); -assertEq(new Set(undefined).size, 0); -assertEq(new Set(null).size, 0); +load(libdir + "asserts.js"); + +var s = new Set(); +assertEq(s.size, 0); +s = new Set(undefined); +assertEq(s.size, 0); +s = new Set(null); +assertEq(s.size, 0); + +// FIXME: bug 1083752 +options("werror"); +assertEq(evaluate("Set()", {catchTermination: true}), "terminated"); +// assertThrowsInstanceOf(() => Set(), TypeError); +// assertThrowsInstanceOf(() => Set(undefined), TypeError); +// assertThrowsInstanceOf(() => Set(null), TypeError); diff --git a/js/src/jit-test/tests/collections/Set-constructor-2.js b/js/src/jit-test/tests/collections/Set-constructor-2.js index 0ec554fc9804..43fffba8e8e3 100644 --- a/js/src/jit-test/tests/collections/Set-constructor-2.js +++ b/js/src/jit-test/tests/collections/Set-constructor-2.js @@ -1,16 +1,16 @@ // The Set constructor can take an argument that is an array. -var s = Set([]); +var s = new Set([]); assertEq(s.size, 0); assertEq(s.has(undefined), false); -s = Set(["one", "two", "three"]); +s = new Set(["one", "two", "three"]); assertEq(s.size, 3); assertEq(s.has("one"), true); assertEq(s.has("eleventeen"), false); var a = [{}, {}, {}]; -s = Set(a); +s = new Set(a); assertEq(s.size, 3); for (let obj of a) assertEq(s.has(obj), true); diff --git a/js/src/jit-test/tests/collections/Set-constructor-3.js b/js/src/jit-test/tests/collections/Set-constructor-3.js index 9851cec39664..07bcd1a1ddf2 100644 --- a/js/src/jit-test/tests/collections/Set-constructor-3.js +++ b/js/src/jit-test/tests/collections/Set-constructor-3.js @@ -1,11 +1,12 @@ // The argument to Set may contain a value multiple times. Duplicates are discarded. -assertEq(Set(["testing", "testing", 123]).size, 2); +var s = new Set(["testing", "testing", 123]); +assertEq(s.size, 2); var values = [undefined, null, false, NaN, 0, -0, 6.022e23, -Infinity, "", "xyzzy", {}, Math.sin]; for (let v of values) { var a = [v, {}, {}, {}, v, {}, v, v]; - var s = Set(a); + s = new Set(a); assertEq(s.size, 5); assertEq(s.has(v), true); } diff --git a/js/src/jit-test/tests/collections/Set-constructor-generator-1.js b/js/src/jit-test/tests/collections/Set-constructor-generator-1.js index 3b2263dacbe0..c2f74bc6bb92 100644 --- a/js/src/jit-test/tests/collections/Set-constructor-generator-1.js +++ b/js/src/jit-test/tests/collections/Set-constructor-generator-1.js @@ -5,7 +5,7 @@ function hexData(n) { yield i.toString(16); } -var s = Set(hexData(256)); +var s = new Set(hexData(256)); assertEq(s.size, 256); assertEq(s.has("0"), true); assertEq(s.has(0), false); diff --git a/js/src/jit-test/tests/collections/Set-constructor-generator-2.js b/js/src/jit-test/tests/collections/Set-constructor-generator-2.js index 6e12cf64962b..13660ac25a1a 100644 --- a/js/src/jit-test/tests/collections/Set-constructor-generator-2.js +++ b/js/src/jit-test/tests/collections/Set-constructor-generator-2.js @@ -1,6 +1,6 @@ // The argument to Set can be a generator-expression. -var s = Set(k * k for (k of [1, 2, 3, 4])); +var s = new Set(k * k for (k of [1, 2, 3, 4])); assertEq(s.size, 4); assertEq(s.has(1), true); assertEq(s.has(4), true); diff --git a/js/src/jit-test/tests/collections/Set-delete-size.js b/js/src/jit-test/tests/collections/Set-delete-size.js index fbd2a1cd608b..524978b8178a 100644 --- a/js/src/jit-test/tests/collections/Set-delete-size.js +++ b/js/src/jit-test/tests/collections/Set-delete-size.js @@ -1,6 +1,6 @@ // set.delete(v) decrements set.size iff the set contained v. -var s = Set(); +var s = new Set(); for (var i = 0; i < 10; i++) s.add(i); diff --git a/js/src/jit-test/tests/collections/Set-iterator-1.js b/js/src/jit-test/tests/collections/Set-iterator-1.js index d53e0eda912a..c0bd8fc5a302 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-1.js +++ b/js/src/jit-test/tests/collections/Set-iterator-1.js @@ -1,6 +1,6 @@ // for-of can be used to iterate over a Set twice. -var set = Set(['a', 'b', 'c']); +var set = new Set(['a', 'b', 'c']); var log = ''; for (let i = 0; i < 2; i++) { diff --git a/js/src/jit-test/tests/collections/Set-iterator-2.js b/js/src/jit-test/tests/collections/Set-iterator-2.js index e43a9ccc291d..32737a285e85 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-2.js +++ b/js/src/jit-test/tests/collections/Set-iterator-2.js @@ -1,6 +1,6 @@ // Nested for-of loops can iterate over a Set. -var map = Set(['a', 'b']); +var map = new Set(['a', 'b']); var log = ''; for (let x of map) { log += x + ':' diff --git a/js/src/jit-test/tests/collections/Set-iterator-3.js b/js/src/jit-test/tests/collections/Set-iterator-3.js index 760eda187023..c337acb2f6bf 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-3.js +++ b/js/src/jit-test/tests/collections/Set-iterator-3.js @@ -1,7 +1,7 @@ // Iterating over a set of objects yields those exact objects. var arr = [{}, {}, {}, [], /xyz/, new Date]; -var set = Set(arr); +var set = new Set(arr); assertEq(set.size, arr.length); var i = 0; diff --git a/js/src/jit-test/tests/collections/Set-iterator-add-1.js b/js/src/jit-test/tests/collections/Set-iterator-add-1.js index 2d1c92011677..9f07929239e9 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-add-1.js +++ b/js/src/jit-test/tests/collections/Set-iterator-add-1.js @@ -1,6 +1,6 @@ // set.iterator() is live: entries added during iteration are visited. -var set = Set([5]); +var set = new Set([5]); var log = ''; for (let x of set) { log += x + ';'; diff --git a/js/src/jit-test/tests/collections/Set-iterator-add-2.js b/js/src/jit-test/tests/collections/Set-iterator-add-2.js index 046fe0dff18d..211614a4cfb3 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-add-2.js +++ b/js/src/jit-test/tests/collections/Set-iterator-add-2.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var set = Set(); +var set = new Set(); var iter0 = set[Symbol.iterator](), iter1 = set[Symbol.iterator](); assertIteratorDone(iter0, undefined); // closes iter0 set.add("x"); diff --git a/js/src/jit-test/tests/collections/Set-iterator-add-remove.js b/js/src/jit-test/tests/collections/Set-iterator-add-remove.js index 0c258d389343..b0d3518dafec 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-add-remove.js +++ b/js/src/jit-test/tests/collections/Set-iterator-add-remove.js @@ -1,6 +1,6 @@ // Removing and re-adding entries while an iterator is live causes the iterator to visit them again. -var set = Set(['a']); +var set = new Set(['a']); var n = 5; for (let v of set) { assertEq(v, 'a'); diff --git a/js/src/jit-test/tests/collections/Set-iterator-gc-1.js b/js/src/jit-test/tests/collections/Set-iterator-gc-1.js index 12f3134820fc..e532b98515fb 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-gc-1.js +++ b/js/src/jit-test/tests/collections/Set-iterator-gc-1.js @@ -4,7 +4,7 @@ load(libdir + "referencesVia.js"); load(libdir + "iteration.js"); var key = {}; -var set = Set([key]); +var set = new Set([key]); var iter = set[Symbol.iterator](); referencesVia(iter, "**UNKNOWN SLOT 0**", set); referencesVia(set, "key", key); diff --git a/js/src/jit-test/tests/collections/Set-iterator-gc-2.js b/js/src/jit-test/tests/collections/Set-iterator-gc-2.js index 95dd296d4166..41979b86a84b 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-gc-2.js +++ b/js/src/jit-test/tests/collections/Set-iterator-gc-2.js @@ -1,7 +1,7 @@ // GC-ing during a for-of loop doesn't crash. var i = 0; -for (var x of Set(Object.getOwnPropertyNames(this))) { +for (var x of new Set(Object.getOwnPropertyNames(this))) { gc(); if (++i >= 20) break; diff --git a/js/src/jit-test/tests/collections/Set-iterator-gc-3.js b/js/src/jit-test/tests/collections/Set-iterator-gc-3.js index 80272d680adf..88c428b0065f 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-gc-3.js +++ b/js/src/jit-test/tests/collections/Set-iterator-gc-3.js @@ -1,20 +1,20 @@ // GC in nested for-loops is safe. var x; -for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) - for (x of Set([1])) +for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) + for (x of new Set([1])) gc(); diff --git a/js/src/jit-test/tests/collections/Set-iterator-order.js b/js/src/jit-test/tests/collections/Set-iterator-order.js index bc89debc66ab..3ac84250765c 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-order.js +++ b/js/src/jit-test/tests/collections/Set-iterator-order.js @@ -1,6 +1,6 @@ // Set iterators produces entries in the order they were inserted. -var set = Set(); +var set = new Set(); var i; for (i = 7; i !== 1; i = i * 7 % 1117) set.add(i); diff --git a/js/src/jit-test/tests/collections/Set-iterator-proxies-1.js b/js/src/jit-test/tests/collections/Set-iterator-proxies-1.js index 6096f15be94c..c3d041d08874 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-proxies-1.js +++ b/js/src/jit-test/tests/collections/Set-iterator-proxies-1.js @@ -1,7 +1,7 @@ // for-of works on a cross-compartment wrapper of a Set. var g = newGlobal(); -var mw = g.eval("Set(['a', 'b', 1, 2])"); +var mw = g.eval("new Set(['a', 'b', 1, 2])"); var log = ''; for (let x of mw) log += x; diff --git a/js/src/jit-test/tests/collections/Set-iterator-proxies-2.js b/js/src/jit-test/tests/collections/Set-iterator-proxies-2.js index d369f0e2ce11..75e4565148c2 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-proxies-2.js +++ b/js/src/jit-test/tests/collections/Set-iterator-proxies-2.js @@ -7,13 +7,13 @@ var g = newGlobal(); var iterator_fn = Set.prototype[Symbol.iterator]; assertThrowsInstanceOf(function () { iterator_fn.call({}); }, TypeError); -assertThrowsInstanceOf(function () { iterator_fn.call(Map()); }, TypeError); -var setw = g.eval("Set(['x', 'y'])"); +assertThrowsInstanceOf(function () { iterator_fn.call(new Map()); }, TypeError); +var setw = g.eval("new Set(['x', 'y'])"); assertIteratorNext(iterator_fn.call(setw), "x"); -var next_fn = Set()[Symbol.iterator]().next; +var next_fn = (new Set())[Symbol.iterator]().next; assertThrowsInstanceOf(function () { next_fn.call({}); }, TypeError); -assertThrowsInstanceOf(function () { next_fn.call(Map()[Symbol.iterator]()); }, TypeError); +assertThrowsInstanceOf(function () { next_fn.call((new Map())[Symbol.iterator]()); }, TypeError); var iterw = setw[Symbol.iterator](); assertIteratorResult(next_fn.call(iterw), "x", false); assertIteratorResult(next_fn.call(iterw), "y", false); diff --git a/js/src/jit-test/tests/collections/Set-iterator-remove-1.js b/js/src/jit-test/tests/collections/Set-iterator-remove-1.js index 50e97c46387a..e25fba2afbc5 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-remove-1.js +++ b/js/src/jit-test/tests/collections/Set-iterator-remove-1.js @@ -1,8 +1,8 @@ // A set iterator can cope with removing the current entry. function test(letters, toRemove) { - var set = Set(letters); - toRemove = Set(toRemove); + var set = new Set(letters); + toRemove = new Set(toRemove); var leftovers = [x for (x of set) if (!toRemove.has(x))].join(""); diff --git a/js/src/jit-test/tests/collections/Set-iterator-remove-2.js b/js/src/jit-test/tests/collections/Set-iterator-remove-2.js index e306ecb63305..e78d8a182f8d 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-remove-2.js +++ b/js/src/jit-test/tests/collections/Set-iterator-remove-2.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var set = Set("abcd"); +var set = new Set("abcd"); var iter = set[Symbol.iterator](); var log = ""; for (let x of iter) { diff --git a/js/src/jit-test/tests/collections/Set-iterator-remove-3.js b/js/src/jit-test/tests/collections/Set-iterator-remove-3.js index 97ee47cdcbf2..fd9f4988333a 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-remove-3.js +++ b/js/src/jit-test/tests/collections/Set-iterator-remove-3.js @@ -2,7 +2,7 @@ load(libdir + "iteration.js"); -var set = Set("abcd"); +var set = new Set("abcd"); var iter = set[Symbol.iterator](); assertIteratorNext(iter, "a"); assertIteratorNext(iter, "b"); diff --git a/js/src/jit-test/tests/collections/Set-iterator-remove-4.js b/js/src/jit-test/tests/collections/Set-iterator-remove-4.js index a8404327185d..78f3b66e642a 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-remove-4.js +++ b/js/src/jit-test/tests/collections/Set-iterator-remove-4.js @@ -3,7 +3,7 @@ load(libdir + "iteration.js"); // Make a set. -var set = Set(); +var set = new Set(); var SIZE = 7; for (var j = 0; j < SIZE; j++) set.add(j); diff --git a/js/src/jit-test/tests/collections/Set-iterator-remove-5.js b/js/src/jit-test/tests/collections/Set-iterator-remove-5.js index a74c1145d2b8..378accc3acb1 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-remove-5.js +++ b/js/src/jit-test/tests/collections/Set-iterator-remove-5.js @@ -2,7 +2,7 @@ // entries to be skipped. var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; -var set = Set(str); +var set = new Set(str); var log = ''; var i = 0; diff --git a/js/src/jit-test/tests/collections/Set-iterator-remove-6.js b/js/src/jit-test/tests/collections/Set-iterator-remove-6.js index ae29a1006ca8..923ae631c05f 100644 --- a/js/src/jit-test/tests/collections/Set-iterator-remove-6.js +++ b/js/src/jit-test/tests/collections/Set-iterator-remove-6.js @@ -4,7 +4,7 @@ load(libdir + "iteration.js"); -var set = Set(); +var set = new Set(); for (var i = 0; i < 32; i++) set.add(i); var iter = set[Symbol.iterator](); diff --git a/js/src/jit-test/tests/collections/Set-size.js b/js/src/jit-test/tests/collections/Set-size.js index fc1c266dd50f..7aca1d3b750f 100644 --- a/js/src/jit-test/tests/collections/Set-size.js +++ b/js/src/jit-test/tests/collections/Set-size.js @@ -1,6 +1,6 @@ // Each Set has its own size. -var s1 = Set(), s2 = Set(); +var s1 = new Set(), s2 = new Set(); for (var i = 0; i < 30; i++) s1.add(i); assertEq(s1.size, 30); diff --git a/js/src/jit-test/tests/collections/Set-surfaces-1.js b/js/src/jit-test/tests/collections/Set-surfaces-1.js index daa6475eb4ed..98f0e6f16d7d 100644 --- a/js/src/jit-test/tests/collections/Set-surfaces-1.js +++ b/js/src/jit-test/tests/collections/Set-surfaces-1.js @@ -14,8 +14,7 @@ assertEq(Set.name, "Set"); assertEq(Object.getPrototypeOf(Set.prototype), Object.prototype); assertEq(Object.prototype.toString.call(Set.prototype), "[object Set]"); -assertEq(Object.prototype.toString.call(new Set), "[object Set]"); -assertEq(Object.prototype.toString.call(Set()), "[object Set]"); +assertEq(Object.prototype.toString.call(new Set()), "[object Set]"); assertEq(Object.keys(Set.prototype).join(), ""); assertEq(Set.prototype.constructor, Set); diff --git a/js/src/jit-test/tests/collections/Set-values-1.js b/js/src/jit-test/tests/collections/Set-values-1.js index bf437c6631d1..31acf42d0777 100644 --- a/js/src/jit-test/tests/collections/Set-values-1.js +++ b/js/src/jit-test/tests/collections/Set-values-1.js @@ -1,6 +1,6 @@ // set.keys(), .values(), and .entries() on an empty set produce empty iterators -var s = Set(); +var s = new Set(); var ki = s.keys(), vi = s.values(), ei = s.entries(); var p = Object.getPrototypeOf(ki); assertEq(Object.getPrototypeOf(vi), p); diff --git a/js/src/jit-test/tests/collections/Set-values-2.js b/js/src/jit-test/tests/collections/Set-values-2.js index 60baa06dff91..11490f7f7972 100644 --- a/js/src/jit-test/tests/collections/Set-values-2.js +++ b/js/src/jit-test/tests/collections/Set-values-2.js @@ -4,7 +4,7 @@ load(libdir + "iteration.js"); var data = [1, 2, 3, 4]; -var s = Set(data); +var s = new Set(data); var ki = s.keys(); assertIteratorNext(ki, 1); diff --git a/js/src/jit-test/tests/collections/WeakMap-clear.js b/js/src/jit-test/tests/collections/WeakMap-clear.js index 0d4b9fc14942..7ceaa6277f32 100644 --- a/js/src/jit-test/tests/collections/WeakMap-clear.js +++ b/js/src/jit-test/tests/collections/WeakMap-clear.js @@ -1,5 +1,5 @@ var key = {}; -var wm = WeakMap(); +var wm = new WeakMap(); assertEq(wm.has(key), false); // Clearing an already empty WeakMap diff --git a/js/src/jit-test/tests/collections/WeakMap-constructor-1.js b/js/src/jit-test/tests/collections/WeakMap-constructor-1.js index 14cbb492922d..826aa1d27416 100644 --- a/js/src/jit-test/tests/collections/WeakMap-constructor-1.js +++ b/js/src/jit-test/tests/collections/WeakMap-constructor-1.js @@ -6,7 +6,9 @@ new WeakMap(); new WeakMap(undefined); new WeakMap(null); -// FIXME: bug 1062075 +// FIXME: bug 1083752 +options("werror"); +assertEq(evaluate("WeakMap()", {catchTermination: true}), "terminated"); // assertThrowsInstanceOf(() => WeakMap(), TypeError); // assertThrowsInstanceOf(() => WeakMap(undefined), TypeError); // assertThrowsInstanceOf(() => WeakMap(null), TypeError); diff --git a/js/src/jit-test/tests/collections/WeakMap-constructor-4.js b/js/src/jit-test/tests/collections/WeakMap-constructor-4.js index 5ff345fe491d..6b87d66f59d3 100644 --- a/js/src/jit-test/tests/collections/WeakMap-constructor-4.js +++ b/js/src/jit-test/tests/collections/WeakMap-constructor-4.js @@ -1,4 +1,4 @@ -// WeakMap(x) throws if x is not iterable (unless x is undefined). +// new WeakMap(x) throws if x is not iterable (unless x is undefined). load(libdir + "asserts.js"); var nonIterables = [true, 1, -0, 3.14, NaN, {}, Math, this]; diff --git a/js/src/jit-test/tests/collections/WeakMap-constructor-5.js b/js/src/jit-test/tests/collections/WeakMap-constructor-5.js index 10ae17ddc176..3ef7300bea83 100644 --- a/js/src/jit-test/tests/collections/WeakMap-constructor-5.js +++ b/js/src/jit-test/tests/collections/WeakMap-constructor-5.js @@ -1,4 +1,4 @@ -// WeakMap(arr) throws if arr contains holes (or undefined values). +// new WeakMap(arr) throws if arr contains holes (or undefined values). load(libdir + "asserts.js"); @@ -14,7 +14,7 @@ assertThrowsInstanceOf(function () { new WeakMap([null]); }, TypeError); assertThrowsInstanceOf(function () { new WeakMap([[k1, v1], [k2, v2], , [k3, k3]]); }, TypeError); assertThrowsInstanceOf(function () { new WeakMap([[k1, v1], [k2, v2], ,]); }, TypeError); -// WeakMap(iterable) throws if iterable doesn't have array-like objects +// new WeakMap(iterable) throws if iterable doesn't have array-like objects assertThrowsInstanceOf(function () { new WeakMap([1, 2, 3]); }, TypeError); assertThrowsInstanceOf(function () { diff --git a/js/src/jit-test/tests/collections/WeakMap-surfaces.js b/js/src/jit-test/tests/collections/WeakMap-surfaces.js index 9ed2f68af2c4..06a93556a176 100644 --- a/js/src/jit-test/tests/collections/WeakMap-surfaces.js +++ b/js/src/jit-test/tests/collections/WeakMap-surfaces.js @@ -12,8 +12,7 @@ assertEq(WeakMap.name, "WeakMap"); assertEq(Object.getPrototypeOf(WeakMap.prototype), Object.prototype); assertEq(Object.prototype.toString.call(WeakMap.prototype), "[object WeakMap]"); -assertEq(Object.prototype.toString.call(new WeakMap), "[object WeakMap]"); -assertEq(Object.prototype.toString.call(WeakMap()), "[object WeakMap]"); +assertEq(Object.prototype.toString.call(new WeakMap()), "[object WeakMap]"); assertEq(Object.keys(WeakMap.prototype).join(), ""); assertEq(WeakMap.prototype.constructor, WeakMap); diff --git a/js/src/jit-test/tests/collections/WeakSet-constructor.js b/js/src/jit-test/tests/collections/WeakSet-constructor.js index 760698189402..a89e8fc0c856 100644 --- a/js/src/jit-test/tests/collections/WeakSet-constructor.js +++ b/js/src/jit-test/tests/collections/WeakSet-constructor.js @@ -4,6 +4,6 @@ var ws = new WeakSet(list); assertEq(ws.has(Number), true); assertEq(ws.has(Function), true); -ws = new WeakSet(Set(list)); +ws = new WeakSet(new Set(list)); assertEq(ws.has(Number), true); assertEq(ws.has(Function), true); diff --git a/js/src/jit-test/tests/collections/constructor-errors.js b/js/src/jit-test/tests/collections/constructor-errors.js index 3d7340f2d01d..d5cbab9e7982 100644 --- a/js/src/jit-test/tests/collections/constructor-errors.js +++ b/js/src/jit-test/tests/collections/constructor-errors.js @@ -17,6 +17,6 @@ var misc = [ ]; for (var v of misc) { - assertThrowsInstanceOf(function () { Set(v); }, TypeError); - assertThrowsInstanceOf(function () { Map(v); }, TypeError); + assertThrowsInstanceOf(function () { new Set(v); }, TypeError); + assertThrowsInstanceOf(function () { new Map(v); }, TypeError); } \ No newline at end of file diff --git a/js/src/jit-test/tests/collections/iterator-gc.js b/js/src/jit-test/tests/collections/iterator-gc.js index f4de54bff9a7..c24d0ef555f4 100644 --- a/js/src/jit-test/tests/collections/iterator-gc.js +++ b/js/src/jit-test/tests/collections/iterator-gc.js @@ -11,6 +11,6 @@ function test(obj, edgeName) { referencesVia(obj, edgeName, key); } -test([key], "element[0]"); -test(Map([[key, 'value']]), "key"); -test(Set([key]), "key"); +test([key], "element[0]"); +test(new Map([[key, 'value']]), "key"); +test(new Set([key]), "key"); diff --git a/js/src/jit-test/tests/collections/iterator-proto-1.js b/js/src/jit-test/tests/collections/iterator-proto-1.js index 69061c6ff78c..f5dd2beb479f 100644 --- a/js/src/jit-test/tests/collections/iterator-proto-1.js +++ b/js/src/jit-test/tests/collections/iterator-proto-1.js @@ -11,5 +11,5 @@ function test(obj0, obj1) { } test([], [1]); -test(Map(), Map([[1, 1]])); -test(Set(), Set([1])); +test(new Map(), new Map([[1, 1]])); +test(new Set(), new Set([1])); diff --git a/js/src/jit-test/tests/collections/iterator-proto-2.js b/js/src/jit-test/tests/collections/iterator-proto-2.js index 5a5a1459f7c2..d6d5ba7d7f69 100644 --- a/js/src/jit-test/tests/collections/iterator-proto-2.js +++ b/js/src/jit-test/tests/collections/iterator-proto-2.js @@ -3,8 +3,8 @@ load(libdir + "iteration.js"); var aproto = Object.getPrototypeOf(Array()[Symbol.iterator]()); -var mproto = Object.getPrototypeOf(Map()[Symbol.iterator]()); -var sproto = Object.getPrototypeOf(Set()[Symbol.iterator]()); +var mproto = Object.getPrototypeOf((new Map())[Symbol.iterator]()); +var sproto = Object.getPrototypeOf((new Set())[Symbol.iterator]()); assertEq(aproto !== mproto, true); assertEq(aproto !== sproto, true); assertEq(mproto !== sproto, true); diff --git a/js/src/jit-test/tests/collections/iterator-proto-surfaces.js b/js/src/jit-test/tests/collections/iterator-proto-surfaces.js index 21012c507a61..0d83c7ab5ddf 100644 --- a/js/src/jit-test/tests/collections/iterator-proto-surfaces.js +++ b/js/src/jit-test/tests/collections/iterator-proto-surfaces.js @@ -4,7 +4,7 @@ load(libdir + "asserts.js"); load(libdir + "iteration.js"); function test(constructor) { - var proto = Object.getPrototypeOf(constructor()[Symbol.iterator]()); + var proto = Object.getPrototypeOf(new constructor()[Symbol.iterator]()); var names = Object.getOwnPropertyNames(proto); names.sort(); assertDeepEq(names, ['next']); diff --git a/js/src/jit-test/tests/debug/onNewScript-01.js b/js/src/jit-test/tests/debug/onNewScript-01.js index c1e691fd15a8..7050a760ee80 100644 --- a/js/src/jit-test/tests/debug/onNewScript-01.js +++ b/js/src/jit-test/tests/debug/onNewScript-01.js @@ -2,7 +2,7 @@ var g = newGlobal(); var dbg = Debugger(g); -var seen = WeakMap(); +var seen = new WeakMap(); var hits = 0; dbg.onNewScript = function (s) { // Exceptions thrown from onNewScript are swept under the rug, but they diff --git a/js/src/jit-test/tests/debug/onNewScript-02.js b/js/src/jit-test/tests/debug/onNewScript-02.js index 79ce163c394e..397c771f37be 100644 --- a/js/src/jit-test/tests/debug/onNewScript-02.js +++ b/js/src/jit-test/tests/debug/onNewScript-02.js @@ -2,7 +2,7 @@ var g = newGlobal(); var dbg = Debugger(g); -var seen = WeakMap(); +var seen = new WeakMap(); var hits; dbg.onNewScript = function (s) { assertEq(s instanceof Debugger.Script, true); diff --git a/js/src/jit-test/tests/gc/bug-880816.js b/js/src/jit-test/tests/gc/bug-880816.js index e11853475b94..7d7e9e622d83 100644 --- a/js/src/jit-test/tests/gc/bug-880816.js +++ b/js/src/jit-test/tests/gc/bug-880816.js @@ -9,7 +9,7 @@ function seq_scan(array, f) {}\ function assertStructuralEq(e1, e2) {}\ for (var i = 0, l = a.length; i < l; i++) {}\ ');"); -lfcode.push("for (var x of Set(Object.getOwnPropertyNames(this))) {}"); +lfcode.push("for (var x of new Set(Object.getOwnPropertyNames(this))) {}"); var lfRunTypeId = -1; while (true) { var file = lfcode.shift(); if (file == undefined) { break; } diff --git a/js/src/jit-test/tests/generators/bug908920.js b/js/src/jit-test/tests/generators/bug908920.js index 53394adec403..4cb781b57222 100644 --- a/js/src/jit-test/tests/generators/bug908920.js +++ b/js/src/jit-test/tests/generators/bug908920.js @@ -1,7 +1,7 @@ if (typeof schedulegc != 'undefined') { Function("\ x = (function() { yield })();\ - Set(x);\ + new Set(x);\ schedulegc(1);\ print( /x/ );\ for (p in x) {}\ diff --git a/js/src/jit-test/tests/ion/bug1124485.js b/js/src/jit-test/tests/ion/bug1124485.js new file mode 100644 index 000000000000..866f83e23a4b --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1124485.js @@ -0,0 +1,7 @@ +function f(x) { + var y = Math.fround(x); + assertEq(y, Math.pow(y, 1)); +} + +f(0); +f(2147483647); diff --git a/js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js b/js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js new file mode 100644 index 000000000000..1de2eaef040f --- /dev/null +++ b/js/src/jit-test/tests/proxy/delete-not-invoked-on-proto.js @@ -0,0 +1,10 @@ +// Create Proxy that throws for everything. +var {proxy, revoke} = Proxy.revocable({}, {}); + +var obj = {__proto__: proxy, a: 1}; +// This revokes the proxy, so every operation on it THROWS. +revoke(); + +assertEq(delete obj.a, true); +assertEq(delete obj.b, true); +// Should not have invoked anything on [[Prototype]] diff --git a/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js b/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js index ec4888753905..11ee4e8d2d9f 100644 --- a/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js +++ b/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js @@ -4,5 +4,5 @@ */ // Don't crash -serialize(evalcx("Set(['x', 'y'])")); -serialize(evalcx("Map([['x', 1]])")); +serialize(evalcx("new Set(['x', 'y'])")); +serialize(evalcx("new Map([['x', 1]])")); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 5c5c12866c60..c1267ee98947 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4595,10 +4595,16 @@ IonBuilder::specializeInlinedReturn(MDefinition *rdef, MBasicBlock *exit) if (rdef->resultTypeSet()->isSubset(types)) return rdef; } else { + MIRType observedType = types->getKnownMIRType(); + + // Don't specialize if type is MIRType_Float32 and TI reports + // MIRType_Double. Float is more specific than double. + if (observedType == MIRType_Double && rdef->type() == MIRType_Float32) + return rdef; + // Don't specialize if types are inaccordance, except for MIRType_Value // and MIRType_Object (when not unknown object), since the typeset // contains more specific information. - MIRType observedType = types->getKnownMIRType(); if (observedType == rdef->type() && observedType != MIRType_Value && (observedType != MIRType_Object || types->unknownObject())) diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index aff0b62e864f..c37de6af2f2e 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -140,17 +140,27 @@ void MacroAssemblerARM::convertFloat32ToInt32(FloatRegister src, Register dest, Label *fail, bool negativeZeroCheck) { - // Convert the floating point value to an integer, if it did not fit, then - // when we convert it *back* to a float, it will have a different value, - // which we can test. - ma_vcvt_F32_I32(src, ScratchFloat32Reg.sintOverlay()); - // Move the value into the dest register. - ma_vxfer(ScratchFloat32Reg, dest); - ma_vcvt_I32_F32(ScratchFloat32Reg.sintOverlay(), ScratchFloat32Reg); - ma_vcmp_f32(src, ScratchFloat32Reg); + // Converting the floating point value to an integer and then converting it + // back to a float32 would not work, as float to int32 conversions are + // clamping (e.g. float(INT32_MAX + 1) would get converted into INT32_MAX + // and then back to float(INT32_MAX + 1)). If this ever happens, we just + // bail out. + FloatRegister ScratchSIntReg = ScratchFloat32Reg.sintOverlay(); + ma_vcvt_F32_I32(src, ScratchSIntReg); + + // Store the result + ma_vxfer(ScratchSIntReg, dest); + + ma_vcvt_I32_F32(ScratchSIntReg, ScratchFloat32Reg); + ma_vcmp(src, ScratchFloat32Reg); as_vmrs(pc); ma_b(fail, Assembler::VFP_NotEqualOrUnordered); + // Bail out in the clamped cases. + ma_cmp(dest, Imm32(0x7fffffff)); + ma_cmp(dest, Imm32(0x80000000), Assembler::NotEqual); + ma_b(fail, Assembler::Equal); + if (negativeZeroCheck) { ma_cmp(dest, Imm32(0)); // Test and bail for -0.0, when integer result is 0. Move the float into diff --git a/js/src/jit/arm/Simulator-arm.cpp b/js/src/jit/arm/Simulator-arm.cpp index 2637dc3a8705..bab36b97a82f 100644 --- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -352,6 +352,31 @@ class CachePage char validity_map_[kValidityMapSize]; // One byte per line. }; +// Protects the icache() and redirection() properties of the +// Simulator. +class AutoLockSimulatorCache +{ + public: + explicit AutoLockSimulatorCache(Simulator *sim) : sim_(sim) { + PR_Lock(sim_->cacheLock_); + MOZ_ASSERT(!sim_->cacheLockHolder_); +#ifdef DEBUG + sim_->cacheLockHolder_ = PR_GetCurrentThread(); +#endif + } + + ~AutoLockSimulatorCache() { + MOZ_ASSERT(sim_->cacheLockHolder_); +#ifdef DEBUG + sim_->cacheLockHolder_ = nullptr; +#endif + PR_Unlock(sim_->cacheLock_); + } + + private: + Simulator *const sim_; +}; + bool Simulator::ICacheCheckingEnabled = false; int64_t Simulator::StopSimAt = -1L; @@ -922,7 +947,7 @@ AllOnOnePage(uintptr_t start, int size) } static CachePage * -GetCachePage(Simulator::ICacheMap &i_cache, void *page) +GetCachePageLocked(Simulator::ICacheMap &i_cache, void *page) { MOZ_ASSERT(Simulator::ICacheCheckingEnabled); @@ -938,7 +963,7 @@ GetCachePage(Simulator::ICacheMap &i_cache, void *page) // Flush from start up to and not including start + size. static void -FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size) +FlushOnePageLocked(Simulator::ICacheMap &i_cache, intptr_t start, int size) { MOZ_ASSERT(size <= CachePage::kPageSize); MOZ_ASSERT(AllOnOnePage(start, size - 1)); @@ -947,13 +972,13 @@ FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size) void *page = reinterpret_cast(start & (~CachePage::kPageMask)); int offset = (start & CachePage::kPageMask); - CachePage *cache_page = GetCachePage(i_cache, page); + CachePage *cache_page = GetCachePageLocked(i_cache, page); char *valid_bytemap = cache_page->validityByte(offset); memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); } static void -FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size) +FlushICacheLocked(Simulator::ICacheMap &i_cache, void *start_addr, size_t size) { intptr_t start = reinterpret_cast(start_addr); int intra_line = (start & CachePage::kLineMask); @@ -963,24 +988,24 @@ FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size) int offset = (start & CachePage::kPageMask); while (!AllOnOnePage(start, size - 1)) { int bytes_to_flush = CachePage::kPageSize - offset; - FlushOnePage(i_cache, start, bytes_to_flush); + FlushOnePageLocked(i_cache, start, bytes_to_flush); start += bytes_to_flush; size -= bytes_to_flush; MOZ_ASSERT((start & CachePage::kPageMask) == 0); offset = 0; } if (size != 0) - FlushOnePage(i_cache, start, size); + FlushOnePageLocked(i_cache, start, size); } static void -CheckICache(Simulator::ICacheMap &i_cache, SimInstruction *instr) +CheckICacheLocked(Simulator::ICacheMap &i_cache, SimInstruction *instr) { intptr_t address = reinterpret_cast(instr); void *page = reinterpret_cast(address & (~CachePage::kPageMask)); void *line = reinterpret_cast(address & (~CachePage::kLineMask)); int offset = (address & CachePage::kPageMask); - CachePage* cache_page = GetCachePage(i_cache, page); + CachePage* cache_page = GetCachePageLocked(i_cache, page); char *cache_valid_byte = cache_page->validityByte(offset); bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); char *cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask); @@ -1021,9 +1046,13 @@ void Simulator::FlushICache(void *start_addr, size_t size) { JitSpewCont(JitSpew_CacheFlush, "[%p %zx]", start_addr, size); - if (!Simulator::ICacheCheckingEnabled) - return; - js::jit::FlushICache(Simulator::Current()->icache(), start_addr, size); + if (Simulator::ICacheCheckingEnabled) { + Simulator *sim = Simulator::Current(); + + AutoLockSimulatorCache als(sim); + + js::jit::FlushICacheLocked(sim->icache(), start_addr, size); + } } Simulator::Simulator() @@ -1079,12 +1108,20 @@ Simulator::Simulator() lastDebuggerInput_ = nullptr; + cacheLock_ = nullptr; +#ifdef DEBUG + cacheLockHolder_ = nullptr; +#endif redirection_ = nullptr; } bool Simulator::init() { + cacheLock_ = PR_NewLock(); + if (!cacheLock_) + return false; + if (!icache_.init()) return false; @@ -1116,6 +1153,7 @@ class Redirection { friend class Simulator; + // sim's lock must already be held. Redirection(void *nativeFunction, ABIFunctionType type, Simulator *sim) : nativeFunction_(nativeFunction), swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected), @@ -1124,7 +1162,7 @@ class Redirection { next_ = sim->redirection(); if (Simulator::ICacheCheckingEnabled) - FlushICache(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize); + FlushICacheLocked(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize); sim->setRedirection(this); } @@ -1135,6 +1173,9 @@ class Redirection static Redirection *Get(void *nativeFunction, ABIFunctionType type) { Simulator *sim = Simulator::Current(); + + AutoLockSimulatorCache als(sim); + Redirection *current = sim->redirection(); for (; current != nullptr; current = current->next_) { if (current->nativeFunction_ == nativeFunction) { @@ -1169,6 +1210,7 @@ class Redirection Simulator::~Simulator() { js_free(stack_); + PR_DestroyLock(cacheLock_); Redirection *r = redirection_; while (r) { Redirection *next = r->next_; @@ -4100,8 +4142,10 @@ Simulator::decodeSpecialCondition(SimInstruction *instr) void Simulator::instructionDecode(SimInstruction *instr) { - if (Simulator::ICacheCheckingEnabled) - CheckICache(icache(), instr); + if (Simulator::ICacheCheckingEnabled) { + AutoLockSimulatorCache als(this); + CheckICacheLocked(icache(), instr); + } pc_modified_ = false; diff --git a/js/src/jit/arm/Simulator-arm.h b/js/src/jit/arm/Simulator-arm.h index 709d894a69ef..c2bf2e5df701 100644 --- a/js/src/jit/arm/Simulator-arm.h +++ b/js/src/jit/arm/Simulator-arm.h @@ -31,6 +31,8 @@ #ifdef JS_ARM_SIMULATOR +#include "jslock.h" + #include "jit/arm/Architecture-arm.h" #include "jit/IonTypes.h" @@ -40,6 +42,7 @@ namespace jit { class Simulator; class Redirection; class CachePage; +class AutoLockSimulator; // When the SingleStepCallback is called, the simulator is about to execute // sim->get_pc() and the current machine state represents the completed @@ -68,6 +71,7 @@ class SimInstruction; class Simulator { friend class Redirection; + friend class AutoLockSimulatorCache; public: friend class ArmDebugger; @@ -383,8 +387,6 @@ class Simulator } private: - Redirection *redirection_; - // ICache checking. struct ICacheHasher { typedef void *Key; @@ -396,19 +398,34 @@ class Simulator public: typedef HashMap ICacheMap; - protected: + private: + // This lock creates a critical section around 'redirection_' and + // 'icache_', which are referenced both by the execution engine + // and by the off-thread compiler (see Redirection::Get in the cpp file). + PRLock *cacheLock_; +#ifdef DEBUG + PRThread *cacheLockHolder_; +#endif + + Redirection *redirection_; ICacheMap icache_; public: ICacheMap &icache() { + // Technically we need the lock to access the innards of the + // icache, not to take its address, but the latter condition + // serves as a useful complement to the former. + MOZ_ASSERT(cacheLockHolder_); return icache_; } Redirection *redirection() const { + MOZ_ASSERT(cacheLockHolder_); return redirection_; } void setRedirection(js::jit::Redirection *redirection) { + MOZ_ASSERT(cacheLockHolder_); redirection_ = redirection; } }; diff --git a/js/src/jit/mips/Simulator-mips.cpp b/js/src/jit/mips/Simulator-mips.cpp index f6c4a2b73270..6ee7755577c7 100644 --- a/js/src/jit/mips/Simulator-mips.cpp +++ b/js/src/jit/mips/Simulator-mips.cpp @@ -486,6 +486,31 @@ class CachePage { char validity_map_[kValidityMapSize]; // One byte per line. }; +// Protects the icache() and redirection() properties of the +// Simulator. +class AutoLockSimulatorCache +{ + public: + explicit AutoLockSimulatorCache(Simulator *sim) : sim_(sim) { + PR_Lock(sim_->cacheLock_); + MOZ_ASSERT(!sim_->cacheLockHolder_); +#ifdef DEBUG + sim_->cacheLockHolder_ = PR_GetCurrentThread(); +#endif + } + + ~AutoLockSimulatorCache() { + MOZ_ASSERT(sim_->cacheLockHolder_); +#ifdef DEBUG + sim_->cacheLockHolder_ = nullptr; +#endif + PR_Unlock(sim_->cacheLock_); + } + + private: + Simulator *const sim_; +}; + bool Simulator::ICacheCheckingEnabled = false; int Simulator::StopSimAt = -1; @@ -497,9 +522,9 @@ Simulator::Create() if (!sim) return nullptr; - if (!sim->icache_.init()) { + if (!sim->init()) { js_delete(sim); - return false; + return nullptr; } if (getenv("MIPS_SIM_ICACHE_CHECKS")) @@ -1117,7 +1142,7 @@ Simulator::setLastDebuggerInput(char *input) } static CachePage * -GetCachePage(Simulator::ICacheMap &i_cache, void *page) +GetCachePageLocked(Simulator::ICacheMap &i_cache, void *page) { Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page); if (p) @@ -1131,7 +1156,7 @@ GetCachePage(Simulator::ICacheMap &i_cache, void *page) // Flush from start up to and not including start + size. static void -FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size) +FlushOnePageLocked(Simulator::ICacheMap &i_cache, intptr_t start, int size) { MOZ_ASSERT(size <= CachePage::kPageSize); MOZ_ASSERT(AllOnOnePage(start, size - 1)); @@ -1139,13 +1164,13 @@ FlushOnePage(Simulator::ICacheMap &i_cache, intptr_t start, int size) MOZ_ASSERT((size & CachePage::kLineMask) == 0); void *page = reinterpret_cast(start & (~CachePage::kPageMask)); int offset = (start & CachePage::kPageMask); - CachePage *cache_page = GetCachePage(i_cache, page); + CachePage *cache_page = GetCachePageLocked(i_cache, page); char *valid_bytemap = cache_page->validityByte(offset); memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); } static void -FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size) +FlushICacheLocked(Simulator::ICacheMap &i_cache, void *start_addr, size_t size) { intptr_t start = reinterpret_cast(start_addr); int intra_line = (start & CachePage::kLineMask); @@ -1155,25 +1180,25 @@ FlushICache(Simulator::ICacheMap &i_cache, void *start_addr, size_t size) int offset = (start & CachePage::kPageMask); while (!AllOnOnePage(start, size - 1)) { int bytes_to_flush = CachePage::kPageSize - offset; - FlushOnePage(i_cache, start, bytes_to_flush); + FlushOnePageLocked(i_cache, start, bytes_to_flush); start += bytes_to_flush; size -= bytes_to_flush; MOZ_ASSERT((start & CachePage::kPageMask) == 0); offset = 0; } if (size != 0) { - FlushOnePage(i_cache, start, size); + FlushOnePageLocked(i_cache, start, size); } } static void -CheckICache(Simulator::ICacheMap &i_cache, SimInstruction *instr) +CheckICacheLocked(Simulator::ICacheMap &i_cache, SimInstruction *instr) { intptr_t address = reinterpret_cast(instr); void *page = reinterpret_cast(address & (~CachePage::kPageMask)); void *line = reinterpret_cast(address & (~CachePage::kLineMask)); int offset = (address & CachePage::kPageMask); - CachePage *cache_page = GetCachePage(i_cache, page); + CachePage *cache_page = GetCachePageLocked(i_cache, page); char *cache_valid_byte = cache_page->validityByte(offset); bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); char *cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask); @@ -1206,7 +1231,11 @@ Simulator::ICacheHasher::match(const Key &k, const Lookup &l) void Simulator::FlushICache(void *start_addr, size_t size) { - js::jit::FlushICache(Simulator::Current()->icache(), start_addr, size); + if (Simulator::ICacheCheckingEnabled) { + Simulator *sim = Simulator::Current(); + AutoLockSimulatorCache als(sim); + js::jit::FlushICacheLocked(sim->icache(), start_addr, size); + } } Simulator::Simulator() @@ -1214,16 +1243,11 @@ Simulator::Simulator() // Set up simulator support first. Some of this information is needed to // setup the architecture state. - // Allocate 2MB for the stack. Note that we will only use 1MB, see below. - static const size_t stackSize = 2 * 1024 * 1024; - stack_ = static_cast(js_malloc(stackSize)); - if (!stack_) { - MOZ_ReportAssertionFailure("[unhandlable oom] Simulator stack", __FILE__, __LINE__); - MOZ_CRASH(); - } - // Leave a safety margin of 1MB to prevent overrunning the stack when - // pushing values (total stack size is 2MB). - stackLimit_ = reinterpret_cast(stack_) + 1024 * 1024; + // Note, allocation and anything that depends on allocated memory is + // deferred until init(), in order to handle OOM properly. + + stack_ = nullptr; + stackLimit_ = 0; pc_modified_ = false; icount_ = 0; break_count_ = 0; @@ -1241,10 +1265,6 @@ Simulator::Simulator() } FCSR_ = 0; - // The sp is initialized to point to the bottom (high address) of the - // allocated stack area. To be safe in potential stack underflows we leave - // some buffer below. - registers_[sp] = reinterpret_cast(stack_) + stackSize - 64; // The ra and pc are initialized to a known bad value that will cause an // access violation if the simulator ever tries to execute it. registers_[pc] = bad_ra; @@ -1255,9 +1275,41 @@ Simulator::Simulator() lastDebuggerInput_ = nullptr; + cacheLock_ = nullptr; +#ifdef DEBUG + cacheLockHolder_ = nullptr; +#endif redirection_ = nullptr; } +bool +Simulator::init() +{ + cacheLock_ = PR_NewLock(); + if (!cacheLock_) + return false; + + if (!icache_.init()) + return false; + + // Allocate 2MB for the stack. Note that we will only use 1MB, see below. + static const size_t stackSize = 2 * 1024 * 1024; + stack_ = static_cast(js_malloc(stackSize)); + if (!stack_) + return false; + + // Leave a safety margin of 1MB to prevent overrunning the stack when + // pushing values (total stack size is 2MB). + stackLimit_ = reinterpret_cast(stack_) + 1024 * 1024; + + // The sp is initialized to point to the bottom (high address) of the + // allocated stack area. To be safe in potential stack underflows we leave + // some buffer below. + registers_[sp] = reinterpret_cast(stack_) + stackSize - 64; + + return true; +} + // When the generated code calls an external reference we need to catch that in // the simulator. The external reference will be a function compiled for the // host architecture. We need to call that function instead of trying to @@ -1269,6 +1321,7 @@ class Redirection { friend class Simulator; + // sim's lock must already be held. Redirection(void* nativeFunction, ABIFunctionType type, Simulator *sim) : nativeFunction_(nativeFunction), swiInstruction_(kCallRedirInstr), @@ -1277,7 +1330,7 @@ class Redirection { next_ = sim->redirection(); if (Simulator::ICacheCheckingEnabled) - FlushICache(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize); + FlushICacheLocked(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize); sim->setRedirection(this); } @@ -1288,6 +1341,9 @@ class Redirection static Redirection *Get(void *nativeFunction, ABIFunctionType type) { Simulator *sim = Simulator::Current(); + + AutoLockSimulatorCache als(sim); + Redirection *current = sim->redirection(); for (; current != nullptr; current = current->next_) { if (current->nativeFunction_ == nativeFunction) { @@ -1322,6 +1378,7 @@ class Redirection Simulator::~Simulator() { js_free(stack_); + PR_DestroyLock(cacheLock_); Redirection *r = redirection_; while (r) { Redirection *next = r->next_; @@ -3213,8 +3270,10 @@ Simulator::decodeTypeJump(SimInstruction *instr) void Simulator::instructionDecode(SimInstruction *instr) { - if (Simulator::ICacheCheckingEnabled) - CheckICache(icache(), instr); + if (Simulator::ICacheCheckingEnabled) { + AutoLockSimulatorCache als(this); + CheckICacheLocked(icache(), instr); + } pc_modified_ = false; switch (instr->instructionType()) { diff --git a/js/src/jit/mips/Simulator-mips.h b/js/src/jit/mips/Simulator-mips.h index d9e1d0eb1d21..4dc79a493aca 100644 --- a/js/src/jit/mips/Simulator-mips.h +++ b/js/src/jit/mips/Simulator-mips.h @@ -31,6 +31,8 @@ #ifdef JS_MIPS_SIMULATOR +#include "jslock.h" + #include "jit/IonTypes.h" namespace js { @@ -39,6 +41,7 @@ namespace jit { class Simulator; class Redirection; class CachePage; +class AutoLockSimulator; const intptr_t kPointerAlignment = 4; const intptr_t kPointerAlignmentMask = kPointerAlignment - 1; @@ -102,6 +105,7 @@ class SimInstruction; class Simulator { friend class Redirection; friend class MipsDebugger; + friend class AutoLockSimulatorCache; public: // Registers are declared in order. See "See MIPS Run Linux" chapter 2. @@ -137,7 +141,9 @@ class Simulator { kNumFPURegisters }; + // Returns nullptr on OOM. static Simulator *Create(); + static void Destroy(Simulator *simulator); // Constructor/destructor are for internal use only; use the static methods above. @@ -224,6 +230,8 @@ class Simulator { Unpredictable = 0xbadbeaf }; + bool init(); + // Unsupported instructions use Format to print an error and stop execution. void format(SimInstruction* instr, const char* format); @@ -354,8 +362,6 @@ class Simulator { StopCountAndDesc watchedStops_[kNumOfWatchedStops]; private: - Redirection *redirection_; - // ICache checking. struct ICacheHasher { typedef void *Key; @@ -367,19 +373,34 @@ class Simulator { public: typedef HashMap ICacheMap; - protected: + private: + // This lock creates a critical section around 'redirection_' and + // 'icache_', which are referenced both by the execution engine + // and by the off-thread compiler (see Redirection::Get in the cpp file). + PRLock *cacheLock_; +#ifdef DEBUG + PRThread *cacheLockHolder_; +#endif + + Redirection *redirection_; ICacheMap icache_; public: ICacheMap &icache() { + // Technically we need the lock to access the innards of the + // icache, not to take its address, but the latter condition + // serves as a useful complement to the former. + MOZ_ASSERT(cacheLockHolder_); return icache_; } Redirection *redirection() const { + MOZ_ASSERT(cacheLockHolder_); return redirection_; } void setRedirection(js::jit::Redirection *redirection) { + MOZ_ASSERT(cacheLockHolder_); redirection_ = redirection; } }; diff --git a/js/src/js.msg b/js/src/js.msg index 93ff92b507f1..6e456b57287d 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -458,3 +458,4 @@ MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol t MSG_DEF(JSMSG_ATOMICS_NOT_INSTALLED, 0, JSEXN_ERR, "futex support is not installed") MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation") MSG_DEF(JSMSG_ATOMICS_TOO_LONG, 0, JSEXN_RANGEERR, "timeout value too large") +MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed on this thread") diff --git a/js/src/jsapi.h b/js/src/jsapi.h index a9bf3de1bf93..4e2ef68f5d6e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -619,15 +619,13 @@ class PerRuntimeFutexAPI // Release the GLOBAL lock. virtual void unlock() = 0; - // Return true iff the calling thread is a worker thread. This must be - // used to guard calls to wait(). The lock need not be held. - virtual bool isOnWorkerThread() = 0; - enum WakeResult { Woken, // Woken by futexWait Timedout, // Woken by timeout - InterruptForTerminate, // Woken by a request to terminate the worker - ErrorTooLong // Implementation constraint on the timer (for now) + ErrorException, // Propagate a pending exception + InterruptForTerminate, // Woken by a request to terminate the worker, throw an uncatchable + WaitingNotAllowed, // wait() was not allowed to block on this thread (permanently) + ErrorTooLong // Implementation limit }; // Block the thread. diff --git a/js/src/json.cpp b/js/src/json.cpp index d24b639643a5..c83f907f31dc 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -836,20 +836,20 @@ json_parse(JSContext *cx, unsigned argc, Value *vp) if (!str) return false; - JSFlatString *flat = str->ensureFlat(cx); - if (!flat) + JSLinearString *linear = str->ensureLinear(cx); + if (!linear) return false; - AutoStableStringChars flatChars(cx); - if (!flatChars.init(cx, flat)) + AutoStableStringChars linearChars(cx); + if (!linearChars.init(cx, linear)) return false; - RootedValue reviver(cx, args.get(1)); + HandleValue reviver = args.get(1); /* Steps 2-5. */ - return flatChars.isLatin1() - ? ParseJSONWithReviver(cx, flatChars.latin1Range(), reviver, args.rval()) - : ParseJSONWithReviver(cx, flatChars.twoByteRange(), reviver, args.rval()); + return linearChars.isLatin1() + ? ParseJSONWithReviver(cx, linearChars.latin1Range(), reviver, args.rval()) + : ParseJSONWithReviver(cx, linearChars.twoByteRange(), reviver, args.rval()); } /* ES5 15.12.3. */ diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 6d7880e12ebe..e183a5375015 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -3537,18 +3537,18 @@ reflect_parse(JSContext *cx, uint32_t argc, jsval *vp) if (!serialize.init(builder)) return false; - JSFlatString *flat = src->ensureFlat(cx); - if (!flat) + JSLinearString *linear = src->ensureLinear(cx); + if (!linear) return false; - AutoStableStringChars flatChars(cx); - if (!flatChars.initTwoByte(cx, flat)) + AutoStableStringChars linearChars(cx); + if (!linearChars.initTwoByte(cx, linear)) return false; CompileOptions options(cx); options.setFileAndLine(filename, lineno); options.setCanLazilyParse(false); - mozilla::Range chars = flatChars.twoByteRange(); + mozilla::Range chars = linearChars.twoByteRange(); Parser parser(cx, &cx->tempLifoAlloc(), options, chars.start().get(), chars.length(), /* foldConstants = */ false, nullptr, nullptr); if (!parser.checkOptions()) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 6ceace7590d5..908e40623ac9 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3065,32 +3065,32 @@ CopySubstringsToFatInline(JSFatInlineString *dest, const CharT *src, const Strin } static inline JSFatInlineString * -FlattenSubstrings(JSContext *cx, Handle flatStr, const StringRange *ranges, +FlattenSubstrings(JSContext *cx, HandleLinearString str, const StringRange *ranges, size_t rangesLen, size_t outputLen) { - JSFatInlineString *str = NewGCFatInlineString(cx); - if (!str) + JSFatInlineString *result = NewGCFatInlineString(cx); + if (!result) return nullptr; AutoCheckCannotGC nogc; - if (flatStr->hasLatin1Chars()) - CopySubstringsToFatInline(str, flatStr->latin1Chars(nogc), ranges, rangesLen, outputLen); + if (str->hasLatin1Chars()) + CopySubstringsToFatInline(result, str->latin1Chars(nogc), ranges, rangesLen, outputLen); else - CopySubstringsToFatInline(str, flatStr->twoByteChars(nogc), ranges, rangesLen, outputLen); - return str; + CopySubstringsToFatInline(result, str->twoByteChars(nogc), ranges, rangesLen, outputLen); + return result; } static JSString * -AppendSubstrings(JSContext *cx, Handle flatStr, - const StringRange *ranges, size_t rangesLen) +AppendSubstrings(JSContext *cx, HandleLinearString str, const StringRange *ranges, + size_t rangesLen) { MOZ_ASSERT(rangesLen); /* For single substrings, construct a dependent string. */ if (rangesLen == 1) - return NewDependentString(cx, flatStr, ranges[0].start, ranges[0].length); + return NewDependentString(cx, str, ranges[0].start, ranges[0].length); - bool isLatin1 = flatStr->hasLatin1Chars(); + bool isLatin1 = str->hasLatin1Chars(); uint32_t fatInlineMaxLength = JSFatInlineString::MAX_LENGTH_TWO_BYTE; if (isLatin1) fatInlineMaxLength = JSFatInlineString::MAX_LENGTH_LATIN1; @@ -3113,10 +3113,10 @@ AppendSubstrings(JSContext *cx, Handle flatStr, if (i == end) { /* Not even one range fits JSFatInlineString, use DependentString */ const StringRange &sr = ranges[i++]; - part = NewDependentString(cx, flatStr, sr.start, sr.length); + part = NewDependentString(cx, str, sr.start, sr.length); } else { /* Copy the ranges (linearly) into a JSFatInlineString */ - part = FlattenSubstrings(cx, flatStr, ranges + i, end - i, substrLen); + part = FlattenSubstrings(cx, str, ranges + i, end - i, substrLen); i = end; } @@ -3134,13 +3134,13 @@ AppendSubstrings(JSContext *cx, Handle flatStr, static bool StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, MutableHandleValue rval) { - Rooted flatStr(cx, str->ensureFlat(cx)); - if (!flatStr) + RootedLinearString linearStr(cx, str->ensureLinear(cx)); + if (!linearStr) return false; Vector ranges; - size_t charsLen = flatStr->length(); + size_t charsLen = linearStr->length(); ScopedMatchPairs matches(&cx->tempLifoAlloc()); size_t startIndex = 0; /* Index used for iterating through the string. */ @@ -3152,7 +3152,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl if (!CheckForInterrupt(cx)) return false; - RegExpRunStatus status = re.execute(cx, flatStr, startIndex, &matches); + RegExpRunStatus status = re.execute(cx, linearStr, startIndex, &matches); if (status == RegExpRunStatus_Error) return false; if (status == RegExpRunStatus_Success_NotFound) @@ -3183,7 +3183,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl res = cx->global()->getRegExpStatics(cx); if (!res) return false; - res->updateLazily(cx, flatStr, &re, lazyIndex); + res->updateLazily(cx, linearStr, &re, lazyIndex); } rval.setString(str); return true; @@ -3194,7 +3194,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl if (!res) return false; - res->updateLazily(cx, flatStr, &re, lazyIndex); + res->updateLazily(cx, linearStr, &re, lazyIndex); /* Include any remaining part of the string. */ if (lastIndex < charsLen) { @@ -3208,7 +3208,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl return true; } - JSString *result = AppendSubstrings(cx, flatStr, ranges.begin(), ranges.length()); + JSString *result = AppendSubstrings(cx, linearStr, ranges.begin(), ranges.length()); if (!result) return false; diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index d7d6555f4a76..6a8175d08d29 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -20,6 +20,7 @@ #include "jsobjinlines.h" #include "vm/Interpreter-inl.h" +#include "vm/NativeObject-inl.h" using namespace js; using namespace js::gc; @@ -526,7 +527,12 @@ WeakMap_construct(JSContext *cx, unsigned argc, Value *vp) if (!obj) return false; - // ES6 23.3.1.1 steps 5-6, 11. + // ES6 draft rev 31 (15 Jan 2015) 23.3.1.1 step 1. + // FIXME: bug 1083752 + if (!WarnIfNotConstructing(cx, args, "WeakMap")) + return false; + + // Steps 5-6, 11. if (!args.get(0).isNullOrUndefined()) { // Steps 7a-b. RootedValue adderVal(cx); diff --git a/js/src/tests/ecma_6/shell.js b/js/src/tests/ecma_6/shell.js index 8bdcb71fff31..f47e781084a8 100644 --- a/js/src/tests/ecma_6/shell.js +++ b/js/src/tests/ecma_6/shell.js @@ -150,8 +150,8 @@ if (typeof assertDeepEq === 'undefined') { } }; - var ab = Map_(); - var bpath = Map_(); + var ab = new Map_(); + var bpath = new Map_(); function check(a, b, path) { if (typeof a === "symbol") { diff --git a/js/src/tests/ecma_7/SIMD/select-bitselect.js b/js/src/tests/ecma_7/SIMD/select-bitselect.js index 81a0aadf359a..c878a6f69147 100644 --- a/js/src/tests/ecma_7/SIMD/select-bitselect.js +++ b/js/src/tests/ecma_7/SIMD/select-bitselect.js @@ -128,9 +128,9 @@ function test() { testSelect(float64x2, inputs); testBitSelectSimple(float64x2, inputs); testBitSelectComplex(float64x2, inputs); - - if (typeof reportCompare === "function") - reportCompare(true, true); } -test(); +// TODO temporarily disabled because of bug 1123404 +//test(); +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/js1_8_5/extensions/findReferences-01.js b/js/src/tests/js1_8_5/extensions/findReferences-01.js index 9d76b0186300..9f12a7c56ca9 100644 --- a/js/src/tests/js1_8_5/extensions/findReferences-01.js +++ b/js/src/tests/js1_8_5/extensions/findReferences-01.js @@ -11,7 +11,7 @@ if (typeof findReferences == "function") { o.myself = o; // self-references should be reported o.alsoMyself = o; // multiple self-references should all be reported - assertEq(referencesVia(o, 'type; type_proto', C.prototype), true); + assertEq(referencesVia(o, 'group; group_proto', C.prototype), true); assertEq(referencesVia(o, 'shape; base; parent', this), true); assertEq(referencesVia(o, 'x', o.x), true); assertEq(referencesVia(o, 'objectElements[42]', o[42]), true); diff --git a/js/src/tests/js1_8_5/extensions/weakmap.js b/js/src/tests/js1_8_5/extensions/weakmap.js index 934975a92d96..4be0c383a649 100644 --- a/js/src/tests/js1_8_5/extensions/weakmap.js +++ b/js/src/tests/js1_8_5/extensions/weakmap.js @@ -80,7 +80,7 @@ function test() } var key = {}; - var map = WeakMap(); + var map = new WeakMap(); check(function() !map.has(key)); map.set(key, 42); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 291ee578d953..423646a4fc52 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -6016,8 +6016,8 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName, const Value &code fullMethodName, "string", InformalValueTypeName(code)); return false; } - Rooted flat(cx, code.toString()->ensureFlat(cx)); - if (!flat) + RootedLinearString linear(cx, code.toString()->ensureLinear(cx)); + if (!linear) return false; /* @@ -6128,7 +6128,7 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName, const Value &code AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr(); jsbytecode *pc = iter ? iter->pc() : nullptr; AutoStableStringChars stableChars(cx); - if (!stableChars.initTwoByte(cx, flat)) + if (!stableChars.initTwoByte(cx, linear)) return false; mozilla::Range chars = stableChars.twoByteRange(); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index aa207b2c43ab..e6e0dc24aa8a 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -2219,6 +2219,53 @@ js::NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receive return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, strict); } +/*** [[Delete]] **********************************************************************************/ + +// ES6 draft rev31 9.1.10 [[Delete]] +bool +js::NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded) +{ + // Steps 2-3. + RootedShape shape(cx); + if (!NativeLookupOwnProperty(cx, obj, id, &shape)) + return false; + + // Step 4. + if (!shape) { + // If no property call the class's delProperty hook, passing succeeded + // as the result parameter. This always succeeds when there is no hook. + return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded); + } + + cx->runtime()->gc.poke(); + + // Step 6. Non-configurable property. + if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT) { + *succeeded = false; + return true; + } + + if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded)) + return false; + if (!*succeeded) + return true; + + // Step 5. + if (IsImplicitDenseOrTypedArrayElement(shape)) { + // Typed array elements are non-configurable. + MOZ_ASSERT(!IsAnyTypedArray(obj)); + + if (!obj->maybeCopyElementsForWrite(cx)) + return false; + + obj->setDenseElementHole(cx, JSID_TO_INT(id)); + } else { + if (!obj->removeProperty(cx, id)) + return false; + } + + return SuppressDeletedProperty(cx, obj, id); +} /* * */ @@ -2253,54 +2300,3 @@ js::NativeSetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId return SetPropertyAttributes(cx, nobj, id, attrsp); } } - -bool -js::NativeDeleteProperty(JSContext *cx, HandleNativeObject obj, HandleId id, bool *succeeded) -{ - RootedObject proto(cx); - RootedShape shape(cx); - if (!NativeLookupProperty(cx, obj, id, &proto, &shape)) - return false; - if (!shape || proto != obj) { - /* - * If no property, or the property comes from a prototype, call the - * class's delProperty hook, passing succeeded as the result parameter. - */ - return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded); - } - - cx->runtime()->gc.poke(); - - if (IsImplicitDenseOrTypedArrayElement(shape)) { - if (IsAnyTypedArray(obj)) { - // Don't delete elements from typed arrays. - *succeeded = false; - return true; - } - - if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded)) - return false; - if (!*succeeded) - return true; - - NativeObject *nobj = &obj->as(); - if (!nobj->maybeCopyElementsForWrite(cx)) - return false; - - nobj->setDenseElementHole(cx, JSID_TO_INT(id)); - return SuppressDeletedProperty(cx, obj, id); - } - - if (!shape->configurable()) { - *succeeded = false; - return true; - } - - RootedId propid(cx, shape->propid()); - if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, propid, succeeded)) - return false; - if (!*succeeded) - return true; - - return obj->removeProperty(cx, id) && SuppressDeletedProperty(cx, obj, id); -} diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 52e3d4b829ec..2eaf2c58e8d4 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 232; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 233; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 367, +static_assert(JSErr_Limit == 368, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " diff --git a/js/xpconnect/idl/nsIXPConnect.idl b/js/xpconnect/idl/nsIXPConnect.idl index f2fcfc3b1920..d9d1295819a9 100644 --- a/js/xpconnect/idl/nsIXPConnect.idl +++ b/js/xpconnect/idl/nsIXPConnect.idl @@ -267,7 +267,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[noscript, uuid(a632b020-331f-11e4-8c21-0800200c9a66)] +[noscript, uuid(f0966cb3-9171-4dc6-a446-37ea16611fb0)] interface nsIXPConnect : nsISupports { %{ C++ @@ -545,13 +545,6 @@ interface nsIXPConnect : nsISupports bool showThisProps) = 0; %} - /** - * Creates a JS object holder around aObject that will hold the object - * alive for as long as the holder stays alive. - */ - nsIXPConnectJSObjectHolder holdObject(in JSContextPtr aJSContext, - in JSObjectPtr aObject); - [noscript] void writeScript(in nsIObjectOutputStream aStream, in JSContextPtr aJSContext, in JSScriptPtr aJSScript); diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index aa7220ddea3f..fe1602058df1 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1194,18 +1194,6 @@ nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const return nullptr; } -NS_IMETHODIMP -nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObjectArg, - nsIXPConnectJSObjectHolder **aHolder) -{ - RootedObject aObject(aJSContext, aObjectArg); - if (!aObject) - return NS_ERROR_FAILURE; - nsRefPtr objHolder = new XPCJSObjectHolder(aObject); - objHolder.forget(aHolder); - return NS_OK; -} - namespace xpc { bool diff --git a/js/xpconnect/tests/chrome/test_getweakmapkeys.xul b/js/xpconnect/tests/chrome/test_getweakmapkeys.xul index d3f8d883426a..90c59fb2c04d 100644 --- a/js/xpconnect/tests/chrome/test_getweakmapkeys.xul +++ b/js/xpconnect/tests/chrome/test_getweakmapkeys.xul @@ -30,12 +30,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=688277 "nondeterministicGetWeakMapKeys should return undefined for null"); /* return an empty array for an empty WeakMap */ - let mempty = WeakMap(); + let mempty = new WeakMap(); is(Cu.nondeterministicGetWeakMapKeys(mempty).length, 0, "nondeterministicGetWeakMapKeys should return empty array for empty weakmap"); /* Test freeing/nonfreeing. */ - let m = WeakMap(); + let m = new WeakMap(); let liveKeys = new Array(); let add_elements = function () { diff --git a/js/xpconnect/tests/chrome/test_weakmap_keys_preserved.xul b/js/xpconnect/tests/chrome/test_weakmap_keys_preserved.xul index 4511badb108c..95908a7b1748 100644 --- a/js/xpconnect/tests/chrome/test_weakmap_keys_preserved.xul +++ b/js/xpconnect/tests/chrome/test_weakmap_keys_preserved.xul @@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=673468 let system = Cc["@mozilla.org/systemprincipal;1"].createInstance(); let sandbox = Cu.Sandbox(system); - let map = sandbox.WeakMap(); + let map = new sandbox.WeakMap(); let obj = {}; map.set(obj, {}); diff --git a/js/xpconnect/tests/mochitest/test_bug655297-1.html b/js/xpconnect/tests/mochitest/test_bug655297-1.html index c1aa879964c2..8f615762fbe4 100644 --- a/js/xpconnect/tests/mochitest/test_bug655297-1.html +++ b/js/xpconnect/tests/mochitest/test_bug655297-1.html @@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=655297 /** Test for Bug 655297 **/ -var map = WeakMap(); +var map = new WeakMap(); function f() { var paras = document.getElementsByTagName("form"); for (var i = 0; i < paras.length; i++) diff --git a/js/xpconnect/tests/mochitest/test_bug655297-2.html b/js/xpconnect/tests/mochitest/test_bug655297-2.html index e88c66b8eccc..2a99557d2f7f 100644 --- a/js/xpconnect/tests/mochitest/test_bug655297-2.html +++ b/js/xpconnect/tests/mochitest/test_bug655297-2.html @@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=655297 /** Test for Bug 655297 **/ -var map = WeakMap(); +var map = new WeakMap(); function f() { var paras = document.getElementsByTagName("p"); for (var i = 0; i < paras.length; i++) diff --git a/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html b/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html index 894b88569e57..e50b1f1bd8ca 100644 --- a/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html +++ b/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html @@ -9,7 +9,7 @@

+ + +
    +
  • item #1
  • +
  • item #2
  • +
  • item #3
  • +
+ + diff --git a/layout/reftests/bugs/1121748-1.html b/layout/reftests/bugs/1121748-1.html new file mode 100644 index 000000000000..85c81a5636c5 --- /dev/null +++ b/layout/reftests/bugs/1121748-1.html @@ -0,0 +1,38 @@ + + + + Bug 1121748-1 + + + + + +
    + +
  • item #2
  • +
  • item #3
  • +
+ + diff --git a/layout/reftests/bugs/1121748-2-ref.html b/layout/reftests/bugs/1121748-2-ref.html new file mode 100644 index 000000000000..782bafaf4e66 --- /dev/null +++ b/layout/reftests/bugs/1121748-2-ref.html @@ -0,0 +1,28 @@ + + + + + + +
+
+ +
+
diff --git a/layout/reftests/bugs/1121748-2.html b/layout/reftests/bugs/1121748-2.html new file mode 100644 index 000000000000..1fa31215deb1 --- /dev/null +++ b/layout/reftests/bugs/1121748-2.html @@ -0,0 +1,34 @@ + + + + + + + +
+
+ + +
+
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 5f69f4f6be26..dedd1eb5dae0 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1858,6 +1858,8 @@ fuzzy-if(d2d,36,304) HTTP(..) == 1116480-1-fakeitalic-overflow.html 1116480-1-fa == 1119117-1b.html 1119117-1-ref.html == 1120431-1.html 1120431-1-ref.html == 1120431-2.html 1120431-2-ref.html +== 1121748-1.html 1121748-1-ref.html +== 1121748-2.html 1121748-2-ref.html == 1127107-1a-nowrap.html 1127107-1-ref.html == 1127107-1b-pre.html 1127107-1-ref.html == 1127107-2-capitalize.html 1127107-2-capitalize-ref.html diff --git a/mfbt/IntegerRange.h b/mfbt/IntegerRange.h new file mode 100644 index 000000000000..44d1d6c80c85 --- /dev/null +++ b/mfbt/IntegerRange.h @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Iterator over ranges of integers */ + +#ifndef mozilla_IntegerRange_h +#define mozilla_IntegerRange_h + +#include "mozilla/Assertions.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/ReverseIterator.h" + +namespace mozilla { + +namespace detail { + +template +class IntegerIterator +{ +public: + typedef const IntTypeT ValueType; + typedef typename MakeSigned::Type DifferenceType; + + template + explicit IntegerIterator(IntType aCurrent) + : mCurrent(aCurrent) { } + + template + IntegerIterator(const IntegerIterator& aOther) + : mCurrent(aOther.mCurrent) { } + + // Since operator* is required to return a reference, we return + // the reference of our member here. + const IntTypeT& operator*() const { return mCurrent; } + + /* Increments and descrements operators */ + + IntegerIterator& operator++() { ++mCurrent; return *this; } + IntegerIterator& operator--() { --mCurrent; return *this; } + IntegerIterator operator++(int) { auto ret = *this; ++mCurrent; return ret; } + IntegerIterator operator--(int) { auto ret = *this; --mCurrent; return ret; } + + IntegerIterator operator+(DifferenceType aN) const + { + return IntegerIterator(mCurrent + aN); + } + IntegerIterator operator-(DifferenceType aN) const + { + return IntegerIterator(mCurrent - aN); + } + IntegerIterator& operator+=(DifferenceType aN) + { + mCurrent += aN; + return *this; + } + IntegerIterator& operator-=(DifferenceType aN) + { + mCurrent -= aN; + return *this; + } + + /* Comparison operators */ + + template + friend bool operator==(const IntegerIterator& aIter1, + const IntegerIterator& aIter2); + template + friend bool operator!=(const IntegerIterator& aIter1, + const IntegerIterator& aIter2); + template + friend bool operator<(const IntegerIterator& aIter1, + const IntegerIterator& aIter2); + template + friend bool operator<=(const IntegerIterator& aIter1, + const IntegerIterator& aIter2); + template + friend bool operator>(const IntegerIterator& aIter1, + const IntegerIterator& aIter2); + template + friend bool operator>=(const IntegerIterator& aIter1, + const IntegerIterator& aIter2); + +private: + IntTypeT mCurrent; +}; + +template +bool operator==(const IntegerIterator& aIter1, + const IntegerIterator& aIter2) +{ + return aIter1.mCurrent == aIter2.mCurrent; +} + +template +bool operator!=(const IntegerIterator& aIter1, + const IntegerIterator& aIter2) +{ + return aIter1.mCurrent != aIter2.mCurrent; +} + +template +bool operator<(const IntegerIterator& aIter1, + const IntegerIterator& aIter2) +{ + return aIter1.mCurrent < aIter2.mCurrent; +} + +template +bool operator<=(const IntegerIterator& aIter1, + const IntegerIterator& aIter2) +{ + return aIter1.mCurrent <= aIter2.mCurrent; +} + +template +bool operator>(const IntegerIterator& aIter1, + const IntegerIterator& aIter2) +{ + return aIter1.mCurrent > aIter2.mCurrent; +} + +template +bool operator>=(const IntegerIterator& aIter1, + const IntegerIterator& aIter2) +{ + return aIter1.mCurrent >= aIter2.mCurrent; +} + +template +class IntegerRange +{ +public: + typedef IntegerIterator iterator; + typedef IntegerIterator const_iterator; + typedef ReverseIterator> reverse_iterator; + typedef ReverseIterator> const_reverse_iterator; + + template + explicit IntegerRange(IntType aEnd) + : mBegin(0), mEnd(aEnd) { } + + template + IntegerRange(IntType1 aBegin, IntType2 aEnd) + : mBegin(aBegin), mEnd(aEnd) { } + + iterator begin() const { return iterator(mBegin); } + const_iterator cbegin() const { return begin(); } + iterator end() const { return iterator(mEnd); } + const_iterator cend() const { return end(); } + reverse_iterator rbegin() const { return reverse_iterator(mEnd); } + const_reverse_iterator crbegin() const { return rbegin(); } + reverse_iterator rend() const { return reverse_iterator(mBegin); } + const_reverse_iterator crend() const { return rend(); } + +private: + IntTypeT mBegin; + IntTypeT mEnd; +}; + +template::value> +struct GeqZero +{ + static bool check(T t) { + return t >= 0; + } +}; + +template +struct GeqZero +{ + static bool check(T t) { + return true; + } +}; + +} // namespace detail + +template +detail::IntegerRange +MakeRange(IntType aEnd) +{ + MOZ_ASSERT(detail::GeqZero::check(aEnd), + "Should never have negative value here"); + return detail::IntegerRange(aEnd); +} + +template +detail::IntegerRange +MakeRange(IntType1 aBegin, IntType2 aEnd) +{ + static_assert(IsSigned::value == IsSigned::value, + "signed/unsigned mismatch"); + MOZ_ASSERT(aEnd >= aBegin, "End value should be larger than begin value"); + return detail::IntegerRange(aBegin, aEnd); +} + +} // namespace mozilla + +#endif // mozilla_IntegerRange_h diff --git a/mfbt/IteratorTraits.h b/mfbt/IteratorTraits.h new file mode 100644 index 000000000000..e7ee622dfa41 --- /dev/null +++ b/mfbt/IteratorTraits.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Iterator traits to expose a value type and a difference type */ + +#ifndef mozilla_IteratorTraits_h +#define mozilla_IteratorTraits_h + +#include + +namespace mozilla { + +template +struct IteratorTraits +{ + typedef typename Iterator::ValueType ValueType; + typedef typename Iterator::DifferenceType DifferenceType; +}; + +template +struct IteratorTraits +{ + typedef T ValueType; + typedef ptrdiff_t DifferenceType; +}; + +template +struct IteratorTraits +{ + typedef const T ValueType; + typedef ptrdiff_t DifferenceType; +}; + +} // namespace mozilla + +#endif // mozilla_IteratorTraits_h diff --git a/mfbt/ReverseIterator.h b/mfbt/ReverseIterator.h new file mode 100644 index 000000000000..e9b2d9b8a040 --- /dev/null +++ b/mfbt/ReverseIterator.h @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* An iterator that acts like another iterator, but iterating in + * the negative direction. (Note that not all iterators can iterate + * in the negative direction.) */ + +#ifndef mozilla_ReverseIterator_h +#define mozilla_ReverseIterator_h + +#include "mozilla/Attributes.h" +#include "mozilla/IteratorTraits.h" + +namespace mozilla { + +template +class ReverseIterator +{ +public: + typedef typename IteratorTraits::ValueType ValueType; + typedef typename IteratorTraits::DifferenceType DifferenceType; + + template + explicit ReverseIterator(Iterator aIter) + : mCurrent(aIter) { } + + template + MOZ_IMPLICIT ReverseIterator(const ReverseIterator& aOther) + : mCurrent(aOther.mCurrent) { } + + ValueType& operator*() const + { + IteratorT tmp = mCurrent; + return *--tmp; + } + + /* Increments and decrements operators */ + + ReverseIterator& operator++() { --mCurrent; return *this; } + ReverseIterator& operator--() { ++mCurrent; return *this; } + ReverseIterator operator++(int) { auto ret = *this; mCurrent--; return ret; } + ReverseIterator operator--(int) { auto ret = *this; mCurrent++; return ret; } + + ReverseIterator operator+(DifferenceType aN) const + { + return ReverseIterator(mCurrent - aN); + } + ReverseIterator operator-(DifferenceType aN) const + { + return ReverseIterator(mCurrent + aN); + } + ReverseIterator& operator+=(DifferenceType aN) + { + mCurrent -= aN; + return *this; + } + ReverseIterator& operator-=(DifferenceType aN) + { + mCurrent += aN; + return *this; + } + + /* Comparison operators */ + + template + friend bool operator==(const ReverseIterator& aIter1, + const ReverseIterator& aIter2); + template + friend bool operator!=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2); + template + friend bool operator<(const ReverseIterator& aIter1, + const ReverseIterator& aIter2); + template + friend bool operator<=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2); + template + friend bool operator>(const ReverseIterator& aIter1, + const ReverseIterator& aIter2); + template + friend bool operator>=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2); + +private: + IteratorT mCurrent; +}; + +template +bool +operator==(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) +{ + return aIter1.mCurrent == aIter2.mCurrent; +} + +template +bool +operator!=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) +{ + return aIter1.mCurrent != aIter2.mCurrent; +} + +template +bool +operator<(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) +{ + return aIter1.mCurrent > aIter2.mCurrent; +} + +template +bool +operator<=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) +{ + return aIter1.mCurrent >= aIter2.mCurrent; +} + +template +bool +operator>(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) +{ + return aIter1.mCurrent < aIter2.mCurrent; +} + +template +bool +operator>=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) +{ + return aIter1.mCurrent <= aIter2.mCurrent; +} + +namespace detail { + +template +class IteratorRange +{ +public: + typedef IteratorT iterator; + typedef IteratorT const_iterator; + typedef ReverseIterator reverse_iterator; + typedef ReverseIterator const_reverse_iterator; + + template + IteratorRange(Iterator1 aIterBegin, Iterator2 aIterEnd) + : mIterBegin(aIterBegin), mIterEnd(aIterEnd) { } + + template + IteratorRange(const IteratorRange& aOther) + : mIterBegin(aOther.mIterBegin), mIterEnd(aOther.mIterEnd) { } + + iterator begin() const { return mIterBegin; } + const_iterator cbegin() const { return begin(); } + iterator end() const { return mIterEnd; } + const_iterator cend() const { return end(); } + reverse_iterator rbegin() const { return reverse_iterator(mIterEnd); } + const_reverse_iterator crbegin() const { return rbegin(); } + reverse_iterator rend() const { return reverse_iterator(mIterBegin); } + const_reverse_iterator crend() const { return rend(); } + +private: + IteratorT mIterBegin; + IteratorT mIterEnd; +}; + +} // namespace detail + +template +detail::IteratorRange +Reversed(Range& aRange) +{ + return {aRange.rbegin(), aRange.rend()}; +} + +template +detail::IteratorRange +Reversed(const Range& aRange) +{ + return {aRange.rbegin(), aRange.rend()}; +} + +} // namespace mozilla + +#endif // mozilla_ReverseIterator_h diff --git a/mfbt/moz.build b/mfbt/moz.build index 7e2f02fac843..82b7e7e7fbea 100644 --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -37,7 +37,9 @@ EXPORTS.mozilla = [ 'GuardObjects.h', 'HashFunctions.h', 'IntegerPrintfMacros.h', + 'IntegerRange.h', 'IntegerTypeTraits.h', + 'IteratorTraits.h', 'JSONWriter.h', 'Likely.h', 'LinkedList.h', @@ -59,6 +61,7 @@ EXPORTS.mozilla = [ 'RefCountType.h', 'ReentrancyGuard.h', 'RefPtr.h', + 'ReverseIterator.h', 'RollingMean.h', 'Scoped.h', 'SegmentedVector.h', diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 0cb71186b4e9..71151f5501da 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -2460,27 +2460,21 @@ public class GeckoAppShell Handler geckoHandler = ThreadUtils.sGeckoHandler; Message msg = getNextMessageFromQueue(ThreadUtils.sGeckoQueue); - if (msg == null) + if (msg == null) { return false; + } + if (msg.obj == geckoHandler && msg.getTarget() == geckoHandler) { // Our "queue is empty" message; see runGecko() - msg.recycle(); return false; } - if (msg.getTarget() == null) - Looper.myLooper().quit(); - else - msg.getTarget().dispatchMessage(msg); - try { - // Bug 1055166 - this sometimes throws IllegalStateException on Android L. - // There appears to be no way to figure out if a message is in use or not, let - // alone receive a notification when it is no longer being used. Just catch - // the exception for now, and if a better solution comes along we can use it. - msg.recycle(); - } catch (IllegalStateException e) { - // There is nothing we can do here so just eat it + if (msg.getTarget() == null) { + Looper.myLooper().quit(); + } else { + msg.getTarget().dispatchMessage(msg); } + return true; } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 899dfbf8f3af..52371321cc63 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -419,10 +419,10 @@ pref("media.getusermedia.screensharing.enabled", true); #endif #ifdef RELEASE_BUILD -pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,example.com"); +pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,example.com"); #else // temporary value, not intended for release - bug 1049087 -pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,example.com"); +pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,example.com"); #endif // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index 8f1a3b2e9864..0d0bfd4caf41 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -1130,7 +1130,7 @@ tt.im tv.im // in : http://en.wikipedia.org/wiki/.in -// see also: http://www.inregistry.in/policies/ +// see also: https://registry.in/Policies // Please note, that nic.in is not an offical eTLD, but used by most // government institutions. in @@ -6780,7 +6780,7 @@ xxx *.zw -// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-12-22T18:02:07Z +// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-01-27T00:02:07Z // abb : 2014-10-24 ABB Ltd abb @@ -6803,6 +6803,9 @@ accountant // accountants : 2014-03-20 Knob Town, LLC accountants +// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +aco + // active : 2014-05-01 The Active Network, Inc active @@ -6833,6 +6836,12 @@ airforce // airtel : 2014-10-24 Bharti Airtel Limited airtel +// alibaba : 2015-01-15 Alibaba Group Holding Limited +alibaba + +// alipay : 2015-01-15 Alibaba Group Holding Limited +alipay + // allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft allfinanz @@ -6848,6 +6857,9 @@ analytics // android : 2014-08-07 Charleston Road Registry Inc. android +// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +anquan + // apartments : 2014-12-11 June Maple, LLC apartments @@ -6887,12 +6899,18 @@ auto // autos : 2014-01-09 DERAutos, LLC autos +// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca +avianca + // axa : 2013-12-19 AXA SA axa // azure : 2014-12-18 Microsoft Corporation azure +// baidu : 2015-01-08 Baidu, Inc. +baidu + // band : 2014-06-12 band @@ -6998,6 +7016,9 @@ bond // boo : 2014-01-30 Charleston Road Registry Inc. boo +// boots : 2015-01-08 THE BOOTS COMPANY PLC +boots + // bot : 2014-12-18 Amazon EU S.à r.l. bot @@ -7010,6 +7031,9 @@ bradesco // bridgestone : 2014-12-18 Bridgestone Corporation bridgestone +// broadway : 2014-12-22 Celebrate Broadway, Inc. +broadway + // broker : 2014-12-11 IG Group Holdings PLC broker @@ -7064,6 +7088,9 @@ capetown // capital : 2014-03-06 Delta Mill, LLC capital +// car : 2015-01-22 Charleston Road Registry Inc. +car + // caravan : 2013-12-12 Caravan International, Inc. caravan @@ -7142,6 +7169,9 @@ church // circle : 2014-12-18 Amazon EU S.à r.l. circle +// cisco : 2014-12-22 Cisco Technology, Inc. +cisco + // citic : 2014-01-09 CITIC Group Corporation citic @@ -7196,6 +7226,9 @@ company // computer : 2013-10-24 Pine Mill, LLC computer +// comsec : 2015-01-08 VeriSign, Inc. +comsec + // condos : 2013-12-05 Pine House, LLC condos @@ -7205,6 +7238,9 @@ construction // consulting : 2013-12-05 consulting +// contact : 2015-01-08 Top Level Spectrum, Inc. +contact + // contractors : 2013-09-10 Magic Woods, LLC contractors @@ -7229,6 +7265,9 @@ credit // creditcard : 2014-03-20 Binky Frostbite, LLC creditcard +// creditunion : 2015-01-22 CUNA Performance Resources, LLC +creditunion + // cricket : 2014-10-09 dot Cricket Limited cricket @@ -7250,6 +7289,9 @@ cuisinella // cymru : 2014-05-08 Nominet UK cymru +// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd. +cyou + // dabur : 2014-02-06 Dabur India Limited dabur @@ -7274,6 +7316,9 @@ day // dclk : 2014-11-20 Charleston Road Registry Inc. dclk +// dealer : 2014-12-22 Dealer Dot Com, Inc. +dealer + // deals : 2014-05-22 Sand Sunset, LLC deals @@ -7343,6 +7388,9 @@ doosan // download : 2014-11-20 dot Support Limited download +// dubai : 2015-01-01 Dubai Smart Government Department +dubai + // durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry durban @@ -7448,6 +7496,9 @@ feedback // ferrero : 2014-12-18 Ferrero Trading Lux S.A. ferrero +// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +film + // final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br final @@ -7580,6 +7631,9 @@ gmo // gmx : 2014-04-24 1&1 Mail & Media GmbH gmx +// gold : 2015-01-22 June Edge, LLC +gold + // goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. goldpoint @@ -7700,6 +7754,9 @@ ibm // ice : 2014-10-30 IntercontinentalExchange, Inc. ice +// icu : 2015-01-08 One.com A/S +icu + // ifm : 2014-01-30 ifm electronic gmbh ifm @@ -7808,6 +7865,12 @@ kiwi // koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH koeln +// komatsu : 2015-01-08 Komatsu Ltd. +komatsu + +// kpn : 2015-01-08 Koninklijke KPN N.V. +kpn + // krd : 2013-12-05 KRG Department of Information Technology krd @@ -7832,6 +7895,9 @@ lat // latrobe : 2014-06-16 La Trobe University latrobe +// law : 2015-01-22 Minds + Machines Group Limited +law + // lawyer : 2014-03-20 lawyer @@ -7859,6 +7925,9 @@ lidl // life : 2014-02-06 Trixy Oaks, LLC life +// lifeinsurance : 2015-01-15 American Council of Life Insurers +lifeinsurance + // lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. lifestyle @@ -7901,6 +7970,9 @@ lotte // lotto : 2014-04-10 Afilias Limited lotto +// love : 2014-12-22 Merchant Law Group LLP +love + // ltd : 2014-09-25 Over Corner, LLC ltd @@ -7925,6 +7997,9 @@ maif // maison : 2013-12-05 Victor Frostbite, LLC maison +// makeup : 2015-01-15 L'Oréal +makeup + // man : 2014-12-04 MAN SE man @@ -8033,6 +8108,9 @@ nagoya // navy : 2014-03-06 United TLD Holdco Ltd. navy +// nec : 2015-01-08 NEC Corporation +nec + // netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA netbank @@ -8066,6 +8144,9 @@ ninja // nissan : 2014-03-27 NISSAN MOTOR CO., LTD. nissan +// nokia : 2015-01-08 Nokia Corporation +nokia + // norton : 2014-12-04 Symantec Corporation norton @@ -8090,6 +8171,9 @@ obi // okinawa : 2013-12-05 BusinessRalliart Inc. okinawa +// omega : 2015-01-08 The Swatch Group Ltd +omega + // one : 2014-11-07 One.com A/S one @@ -8099,6 +8183,9 @@ ong // onl : 2013-09-16 I-Registry Ltd. onl +// online : 2015-01-15 DotOnline Inc. +online + // ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED ooo @@ -8168,6 +8255,9 @@ pictet // pictures : 2014-03-06 Foggy Sky, LLC pictures +// pid : 2015-01-08 Top Level Spectrum, Inc. +pid + // pin : 2014-12-18 Amazon EU S.à r.l. pin @@ -8324,6 +8414,9 @@ saarland // safe : 2014-12-18 Amazon EU S.à r.l. safe +// safety : 2015-01-08 Safety Registry Services, LLC. +safety + // sakura : 2014-12-18 SAKURA Internet Inc. sakura @@ -8423,12 +8516,21 @@ shiksha // shoes : 2013-10-02 Binky Galley, LLC shoes +// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +shouji + // shriram : 2014-01-23 Shriram Capital Ltd. shriram // singles : 2013-08-27 Fern Madison, LLC singles +// site : 2015-01-15 DotSite Inc. +site + +// skin : 2015-01-15 L'Oréal +skin + // sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch sky @@ -8453,6 +8555,9 @@ solar // solutions : 2013-11-07 Silver Cover, LLC solutions +// sony : 2015-01-08 Sony Corporation +sony + // soy : 2014-01-23 Charleston Road Registry Inc. soy @@ -8468,6 +8573,9 @@ spreadbetting // stada : 2014-11-13 STADA Arzneimittel AG stada +// star : 2015-01-08 Star India Private Limited +star + // statoil : 2014-12-04 Statoil ASA statoil @@ -8480,12 +8588,18 @@ stcgroup // stockholm : 2014-12-18 Stockholms kommun stockholm +// storage : 2014-12-22 Self Storage Company LLC +storage + // study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD study // style : 2014-12-04 Binky Moon, LLC style +// sucks : 2014-12-22 Vox Populi Registry Inc. +sucks + // supplies : 2013-12-19 Atomic Fields, LLC supplies @@ -8504,6 +8618,9 @@ surgery // suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION suzuki +// swatch : 2015-01-08 The Swatch Group Ltd +swatch + // swiss : 2014-10-16 Swiss Confederation swiss @@ -8522,6 +8639,9 @@ tab // taipei : 2014-07-10 Taipei City Government taipei +// taobao : 2015-01-15 Alibaba Group Holding Limited +taobao + // tatar : 2014-04-24 Limited Liability Company \ tatar @@ -8558,6 +8678,9 @@ tires // tirol : 2014-04-24 punkt Tirol GmbH tirol +// tmall : 2015-01-15 Alibaba Group Holding Limited +tmall + // today : 2013-09-20 Pearl Woods, LLC today @@ -8576,6 +8699,9 @@ toray // toshiba : 2014-04-10 TOSHIBA Corporation toshiba +// tours : 2015-01-22 Sugar Station, LLC +tours + // town : 2014-03-06 Koko Moon, LLC town @@ -8639,6 +8765,9 @@ video // villas : 2013-12-05 New Sky, LLC villas +// vip : 2015-01-22 Minds + Machines Group Limited +vip + // virgin : 2014-09-25 Virgin Enterprises Limited virgin @@ -8687,6 +8816,12 @@ wanggou // watch : 2013-11-14 Sand Shadow, LLC watch +// watches : 2014-12-22 Richemont DNS Inc. +watches + +// weather : 2015-01-08 The Weather Channel, LLC +weather + // webcam : 2014-01-23 dot Webcam Limited webcam @@ -8741,9 +8876,15 @@ xbox // xerox : 2014-10-24 Xerox DNHC LLC xerox +// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +xihuan + // xin : 2014-12-11 Elegant Leader Limited xin +// xn--11b4c3d : 2015-01-15 VeriSign Sarl +कॉम + // xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. 佛山 @@ -8756,6 +8897,12 @@ xin // xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED 在线 +// xn--3pxu8k : 2015-01-15 VeriSign Sarl +点看 + +// xn--42c2d9a : 2015-01-15 VeriSign Sarl +คอม + // xn--45q11c : 2013-11-21 Zodiac Scorpio Limited 八卦 @@ -8768,6 +8915,9 @@ xin // xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) 公司 +// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +网站 + // xn--6frz82g : 2013-09-23 Afilias Limited 移动 @@ -8783,6 +8933,9 @@ xin // xn--80aswg : 2013-07-14 CORE Association сайт +// xn--9dbq2a : 2015-01-15 VeriSign Sarl +קום + // xn--9et52u : 2014-06-12 RISE VICTORY LIMITED 时尚 @@ -8792,6 +8945,9 @@ xin // xn--c1avg : 2013-11-14 Public Interest Registry орг +// xn--c2br7g : 2015-01-15 VeriSign Sarl +नेट + // xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD 삼성 @@ -8813,6 +8969,9 @@ xin // xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社 新闻 +// xn--fhbei : 2015-01-15 VeriSign Sarl +كوم + // xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED 中文网 @@ -8837,9 +8996,18 @@ xin // xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) 网络 +// xn--j1aef : 2015-01-15 VeriSign Sarl +ком + +// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation +诺基亚 + // xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. 飞利浦 +// xn--kpu716f : 2014-12-22 Richemont DNS Inc. +手表 + // xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd 手机 @@ -8855,6 +9023,9 @@ xin // xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. همراه +// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +닷컴 + // xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. 政府 @@ -8876,6 +9047,12 @@ xin // xn--p1acf : 2013-12-12 Rusnames Limited рус +// xn--pbt977c : 2014-12-22 Richemont DNS Inc. +珠宝 + +// xn--pssy2u : 2015-01-15 VeriSign Sarl +大拿 + // xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. みんな @@ -8885,9 +9062,15 @@ xin // xn--rhqv96g : 2013-09-11 Stable Tone Limited 世界 -// xn--ses554g : 2014-01-16 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED +// xn--ses554g : 2014-01-16 网址 +// xn--t60b56a : 2015-01-15 VeriSign Sarl +닷넷 + +// xn--tckwe : 2015-01-15 VeriSign Sarl +コム + // xn--unup4y : 2013-07-14 Spring Fields, LLC 游戏 @@ -8933,6 +9116,9 @@ yokohama // youtube : 2014-05-01 Charleston Road Registry Inc. youtube +// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD. +yun + // zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) zara @@ -8948,6 +9134,7 @@ zone // zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) zuerich + // ===END ICANN DOMAINS=== // ===BEGIN PRIVATE DOMAINS=== @@ -9074,6 +9261,10 @@ co.ca co.nl co.no +// Commerce Guys, SAS +// Submitted by Damien Tournoud 2015-01-22 +*.platform.sh + // Cupcake : https://cupcake.io/ // Submitted by Jonathan Rudenberg 2013-10-08 cupcake.is diff --git a/netwerk/protocol/http/SpdySession31.cpp b/netwerk/protocol/http/SpdySession31.cpp index 9875b267a6b1..cc2ccd9aec66 100644 --- a/netwerk/protocol/http/SpdySession31.cpp +++ b/netwerk/protocol/http/SpdySession31.cpp @@ -733,14 +733,12 @@ SpdySession31::GenerateRstStream(uint32_t aStatusCode, uint32_t aID) aStatusCode = PR_htonl(aStatusCode); memcpy(packet + 12, &aStatusCode, 4); -#ifdef DEBUG // Intentionally crash on debug builds when the debug 1102923 pref is set // We hope to get useful stack traces to solve bug 1102923 when running // test_spdy.js if (gHttpHandler->Debug1102923()) { MOZ_CRASH("Debug 1102923"); } -#endif LogIO(this, nullptr, "Generate Reset", packet, 16); FlushOutputQueue(); diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 6b6d7131c290..a077cce11946 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -1934,7 +1934,7 @@ class Mochitest(MochitestUtilsMixin): processLeakLog(self.leak_report_file, options) if self.nsprLogs: - with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip: + with zipfile.ZipFile("%s/nsprlog.zip" % self.browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip: for logfile in glob.glob("%s/nspr*.log*" % tempfile.gettempdir()): logzip.write(logfile) os.remove(logfile) diff --git a/testing/web-platform/meta/media-source/mediasource-append-buffer.html.ini b/testing/web-platform/meta/media-source/mediasource-append-buffer.html.ini index 5b4a0ce75ac0..acacb564c3b6 100644 --- a/testing/web-platform/meta/media-source/mediasource-append-buffer.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-append-buffer.html.ini @@ -1,23 +1,22 @@ [mediasource-append-buffer.html] type: testharness - expected: - if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT + disabled: + if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332 + [Test MediaSource.removeSourceBuffer() call during a pending appendBuffer().] expected: FAIL [Test appendBuffer with partial init segments.] expected: - if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL + if (os == "win") and (version != "5.1.2600"): FAIL + if os == "mac": FAIL [Test appendBuffer with partial media segments.] expected: - if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL + if (os == "win") and (version != "5.1.2600"): FAIL + if os == "mac": FAIL [Test abort in the middle of an initialization segment.] - expected: - if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): TIMEOUT - if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): TIMEOUT + disabled: + if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332 diff --git a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-a-bitrate.html.ini b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-a-bitrate.html.ini index 337c329ed9e3..caed3e8601ad 100644 --- a/testing/web-platform/meta/media-source/mediasource-config-change-mp4-a-bitrate.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-config-change-mp4-a-bitrate.html.ini @@ -1,4 +1,11 @@ [mediasource-config-change-mp4-a-bitrate.html] type: testharness + disabled: + if (os == "win") and (version != "5.1.2600"): occasional timeout [Tests mp4 audio-only bitrate changes.] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1106776 + disabled: + if (os == "win") and (version != "5.1.2600"): occasional timeout. + expected: + if os == "mac": PASS + FAIL + diff --git a/testing/web-platform/meta/media-source/mediasource-duration.html.ini b/testing/web-platform/meta/media-source/mediasource-duration.html.ini index dba62e35b1cd..8c85db357a09 100644 --- a/testing/web-platform/meta/media-source/mediasource-duration.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-duration.html.ini @@ -1,27 +1,19 @@ [mediasource-duration.html] type: testharness - expected: - if (os == "win") and (version != "5.1.2600"): OK - if os == "mac": OK - TIMEOUT + disabled: + if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332 + [Test seek starts on duration truncation below currentTime] - expected: - if (os == "win") and (version != "5.1.2600"): FAIL - if os == "mac": FAIL - TIMEOUT + expected: FAIL [Test appendBuffer completes previous seek to truncated duration] - expected: - if (os == "win") and (version != "5.1.2600"): FAIL - if os == "mac": FAIL - TIMEOUT + expected: FAIL [Test endOfStream completes previous seek to truncated duration] - expected: - if (os == "win") and (version != "5.1.2600"): FAIL - if os == "mac": FAIL - TIMEOUT + expected: FAIL [Test setting same duration multiple times does not fire duplicate durationchange] - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1116007 + disabled: + if (os == "win") and (version != "5.1.2600"): https://bugzilla.mozilla.org/show_bug.cgi?id=1128332 + expected: FAIL diff --git a/testing/web-platform/meta/media-source/mediasource-remove.html.ini b/testing/web-platform/meta/media-source/mediasource-remove.html.ini index 62048138c7d9..0859573d9747 100644 --- a/testing/web-platform/meta/media-source/mediasource-remove.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-remove.html.ini @@ -20,6 +20,6 @@ [Test remove with a start at the duration.] expected: - if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL + if (os == "win") and (version != "5.1.2600"): FAIL + if os == "mac": FAIL diff --git a/testing/web-platform/meta/media-source/mediasource-removesourcebuffer.html.ini b/testing/web-platform/meta/media-source/mediasource-removesourcebuffer.html.ini index 6acb4f958c0b..43573f3cb9f9 100644 --- a/testing/web-platform/meta/media-source/mediasource-removesourcebuffer.html.ini +++ b/testing/web-platform/meta/media-source/mediasource-removesourcebuffer.html.ini @@ -2,6 +2,6 @@ type: testharness [Test removesourcebuffer event on activeSourceBuffers.] expected: - if not debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL + if (os == "win") and (version != "5.1.2600"): FAIL + if os == "mac": FAIL diff --git a/toolkit/devtools/server/tests/unit/test_breakpoint-actor-map.js b/toolkit/devtools/server/tests/unit/test_breakpoint-actor-map.js index 995b5bd3da8f..3b8184484ce7 100644 --- a/toolkit/devtools/server/tests/unit/test_breakpoint-actor-map.js +++ b/toolkit/devtools/server/tests/unit/test_breakpoint-actor-map.js @@ -121,7 +121,7 @@ function test_find_actors() { // All breakpoints - let bpSet = Set(bps); + let bpSet = new Set(bps); for (let bp of bpStore.findActors()) { bpSet.delete(bp); } @@ -130,7 +130,7 @@ function test_find_actors() { // Breakpoints by URL - bpSet = Set(bps.filter(bp => { return bp.sourceActor.actorID === "actor1" })); + bpSet = new Set(bps.filter(bp => { return bp.sourceActor.actorID === "actor1" })); for (let bp of bpStore.findActors({ sourceActor: { actorID: "actor1" } })) { bpSet.delete(bp); } @@ -139,7 +139,7 @@ function test_find_actors() { // Breakpoints by URL and line - bpSet = Set(bps.filter(bp => { return bp.sourceActor.actorID === "actor1" && bp.line === 10; })); + bpSet = new Set(bps.filter(bp => { return bp.sourceActor.actorID === "actor1" && bp.line === 10; })); let first = true; for (let bp of bpStore.findActors({ sourceActor: { actorID: "actor1" }, line: 10 })) { if (first) { diff --git a/toolkit/devtools/server/tests/unit/test_forwardingprefix.js b/toolkit/devtools/server/tests/unit/test_forwardingprefix.js index b14afc7737ed..387f28de4db7 100644 --- a/toolkit/devtools/server/tests/unit/test_forwardingprefix.js +++ b/toolkit/devtools/server/tests/unit/test_forwardingprefix.js @@ -104,7 +104,7 @@ function tryActors(aReachables, aCompleted) { */ function TestNoForwardingYet() { - tryActors(Set(['root']), run_next_test); + tryActors(new Set(['root']), run_next_test); } /* @@ -138,7 +138,7 @@ function createSubconnection1() // Establish forwarding, but don't put any actors in that server. function TestForwardPrefix1OnlyRoot() { - tryActors(Set(['root', 'prefix1/root']), run_next_test); + tryActors(new Set(['root', 'prefix1/root']), run_next_test); } /* Create a third root actor, to which we can forward things. */ @@ -152,7 +152,7 @@ function createSubconnection2() function TestForwardPrefix12OnlyRoot() { - tryActors(Set(['root', 'prefix1/root', 'prefix2/root']), run_next_test); + tryActors(new Set(['root', 'prefix1/root', 'prefix2/root']), run_next_test); } // A dumb actor that implements 'echo'. @@ -183,7 +183,7 @@ function TestForwardPrefix12WithActor1() actor.actorID = 'prefix1/actor'; gSubconnection1.addActor(actor); - tryActors(Set(['root', 'prefix1/root', 'prefix1/actor', 'prefix2/root']), run_next_test); + tryActors(new Set(['root', 'prefix1/root', 'prefix1/actor', 'prefix2/root']), run_next_test); } function TestForwardPrefix12WithActor12() @@ -192,5 +192,5 @@ function TestForwardPrefix12WithActor12() actor.actorID = 'prefix2/actor'; gSubconnection2.addActor(actor); - tryActors(Set(['root', 'prefix1/root', 'prefix1/actor', 'prefix2/root', 'prefix2/actor']), run_next_test); + tryActors(new Set(['root', 'prefix1/root', 'prefix1/actor', 'prefix2/root', 'prefix2/actor']), run_next_test); } diff --git a/toolkit/mozapps/installer/package-name.mk b/toolkit/mozapps/installer/package-name.mk index 3c13c66da8d5..8689b2157178 100644 --- a/toolkit/mozapps/installer/package-name.mk +++ b/toolkit/mozapps/installer/package-name.mk @@ -21,7 +21,7 @@ MOZ_PKG_PLATFORM := $(TARGET_OS)-$(TARGET_CPU) # TARGET_OS/TARGET_CPU may be unintuitive, so we hardcode some special formats ifeq ($(OS_ARCH),WINNT) ifeq ($(TARGET_CPU),x86_64) -MOZ_PKG_PLATFORM := win64-$(TARGET_CPU) +MOZ_PKG_PLATFORM := win64 else MOZ_PKG_PLATFORM := win32 endif diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index e57e897f690a..98e705ae375f 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -37,7 +37,13 @@ #include "libdisplay/FramebufferSurface.h" #include "gfxPrefs.h" #include "nsThreadUtils.h" +#endif +#if ANDROID_VERSION >= 21 +#ifndef HWC_BLIT +#define HWC_BLIT 0xFF +#endif +#elif ANDROID_VERSION >= 17 #ifndef HWC_BLIT #define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1) #endif diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 8d84533eaf52..a45e9630866f 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -14,6 +14,7 @@ #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/ReverseIterator.h" #include "mozilla/TypeTraits.h" #include @@ -768,6 +769,10 @@ public: typedef nsTArray_Impl self_type; typedef nsTArrayElementTraits elem_traits; typedef nsTArray_SafeElementAtHelper safeelementat_helper_type; + typedef elem_type* iterator; + typedef const elem_type* const_iterator; + typedef mozilla::ReverseIterator reverse_iterator; + typedef mozilla::ReverseIterator const_reverse_iterator; using safeelementat_helper_type::SafeElementAt; using base_type::EmptyHdr; @@ -991,6 +996,22 @@ public: return SafeElementAt(Length() - 1, aDef); } + // Methods for range-based for loops. + iterator begin() { return Elements(); } + const_iterator begin() const { return Elements(); } + const_iterator cbegin() const { return begin(); } + iterator end() { return Elements() + Length(); } + const_iterator end() const { return Elements() + Length(); } + const_iterator cend() const { return end(); } + + // Methods for reverse iterating. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return rbegin(); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return rend(); } + // // Search methods // @@ -1027,8 +1048,9 @@ public: index_type IndexOf(const Item& aItem, index_type aStart, const Comparator& aComp) const { - const elem_type* iter = Elements() + aStart, *end = Elements() + Length(); - for (; iter != end; ++iter) { + const elem_type* iter = Elements() + aStart; + const elem_type* iend = Elements() + Length(); + for (; iter != iend; ++iter) { if (aComp.Equals(*iter, aItem)) { return index_type(iter - Elements()); } @@ -1060,8 +1082,9 @@ public: const Comparator& aComp) const { size_type endOffset = aStart >= Length() ? Length() : aStart + 1; - const elem_type* end = Elements() - 1, *iter = end + endOffset; - for (; iter != end; --iter) { + const elem_type* iend = Elements() - 1; + const elem_type* iter = iend + endOffset; + for (; iter != iend; --iter) { if (aComp.Equals(*iter, aItem)) { return index_type(iter - Elements()); } @@ -1541,8 +1564,9 @@ public: } // Initialize the extra array elements - elem_type* iter = Elements() + aIndex, *end = iter + aCount; - for (; iter != end; ++iter) { + elem_type* iter = Elements() + aIndex; + elem_type* iend = iter + aCount; + for (; iter != iend; ++iter) { elem_traits::Construct(iter); } @@ -1566,8 +1590,9 @@ public: } // Initialize the extra array elements - elem_type* iter = Elements() + aIndex, *end = iter + aCount; - for (; iter != end; ++iter) { + elem_type* iter = Elements() + aIndex; + elem_type* iend = iter + aCount; + for (; iter != iend; ++iter) { elem_traits::Construct(iter, aItem); } @@ -1696,8 +1721,9 @@ protected: // @param aCount The number of elements to destroy. void DestructRange(index_type aStart, size_type aCount) { - elem_type* iter = Elements() + aStart, *end = iter + aCount; - for (; iter != end; ++iter) { + elem_type* iter = Elements() + aStart; + elem_type *iend = iter + aCount; + for (; iter != iend; ++iter) { elem_traits::Destruct(iter); } } @@ -1722,19 +1748,19 @@ protected: { elem_type* elem = Elements(); elem_type item = elem[aIndex]; - index_type end = Length() - 1; - while ((aIndex * 2) < end) { + index_type iend = Length() - 1; + while ((aIndex * 2) < iend) { const index_type left = (aIndex * 2) + 1; const index_type right = (aIndex * 2) + 2; const index_type parent_index = aIndex; if (aComp.LessThan(item, elem[left])) { - if (left < end && + if (left < iend && aComp.LessThan(elem[left], elem[right])) { aIndex = right; } else { aIndex = left; } - } else if (left < end && + } else if (left < iend && aComp.LessThan(item, elem[right])) { aIndex = right; } else {