diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index be1abad75379..a1c4fdf9b670 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3745,6 +3745,7 @@ var XULBrowserWindow = { aMaxTotalProgress); }, + // This function fires only for the currently selected tab. onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) { const nsIWebProgressListener = Ci.nsIWebProgressListener; const nsIChannel = Ci.nsIChannel; @@ -3752,8 +3753,13 @@ var XULBrowserWindow = { if (aStateFlags & nsIWebProgressListener.STATE_START && aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) { - if (aRequest && aWebProgress.DOMWindow == content) - this.startDocumentLoad(aRequest); + if (aRequest && aWebProgress.DOMWindow == content) { + // clear out feed data + gBrowser.selectedBrowser.feeds = null; + + // clear out search-engine data + gBrowser.selectedBrowser.engines = null; + } this.isBusy = true; @@ -3770,11 +3776,6 @@ var XULBrowserWindow = { } } else if (aStateFlags & nsIWebProgressListener.STATE_STOP) { - if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK && - aWebProgress.DOMWindow == content && - aRequest) - this.endDocumentLoad(aRequest, aStatus); - // This (thanks to the filter) is a network stop or the last // request stop outside of loading the document, stop throbbers // and progress bars and such @@ -4073,30 +4074,6 @@ var XULBrowserWindow = { if (loadingDone) return; this.onStatusChange(gBrowser.webProgress, null, 0, aMessage); - }, - - startDocumentLoad: function XWB_startDocumentLoad(aRequest) { - // clear out feed data - gBrowser.selectedBrowser.feeds = null; - - // clear out search-engine data - gBrowser.selectedBrowser.engines = null; - - var uri = aRequest.QueryInterface(Ci.nsIChannel).URI; - try { - Services.obs.notifyObservers(content, "StartDocumentLoad", uri.spec); - } catch (e) { - } - }, - - endDocumentLoad: function XWB_endDocumentLoad(aRequest, aStatus) { - var urlStr = aRequest.QueryInterface(Ci.nsIChannel).originalURI.spec; - - var notification = Components.isSuccessCode(aStatus) ? "EndDocumentLoad" : "FailDocumentLoad"; - try { - Services.obs.notifyObservers(content, notification, urlStr); - } catch (e) { - } } }; diff --git a/build/autoconf/android.m4 b/build/autoconf/android.m4 index 2144d6e9f980..a3ceccd906d0 100644 --- a/build/autoconf/android.m4 +++ b/build/autoconf/android.m4 @@ -254,7 +254,7 @@ if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then fi STLPORT_SOURCES="$android_ndk/sources/cxx-stl/stlport" STLPORT_CPPFLAGS="-I$_objdir/build/stlport -I$android_ndk/sources/cxx-stl/stlport/stlport" - STLPORT_LIBS="-lstlport_static" + STLPORT_LIBS="-lstlport_static -static-libstdc++" elif test "$target" != "arm-android-eabi"; then dnl fail if we're not building with NDKr4 AC_MSG_ERROR([Couldn't find path to stlport in the android ndk]) diff --git a/build/stlport/stl/config/_android.h.in b/build/stlport/stl/config/_android.h.in index bfe6b32ee39f..17ca9896f478 100644 --- a/build/stlport/stl/config/_android.h.in +++ b/build/stlport/stl/config/_android.h.in @@ -24,4 +24,8 @@ #undef _STLP_NATIVE_CPP_RUNTIME_HEADER #define _STLP_NATIVE_CPP_RUNTIME_HEADER(header) <../../system/include/header> +// Use operator new instead of stlport own node allocator +#undef _STLP_USE_NEWALLOC +#define _STLP_USE_NEWALLOC 1 + #endif /* mozilla_stl_config__android_h */ diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp index 2601738b7c8c..10490dc1b940 100644 --- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -631,13 +631,6 @@ class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL return NS_OK; } - NS_IMETHOD GetExplicitNonHeap(int64_t *aResult) - { - // All of this reporter's memory is on the heap. - *aResult = 0; - return NS_OK; - } - NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *aCallback, nsISupports *aClosure) { diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 27a9c672de53..21efd138e7c9 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -45,6 +45,7 @@ GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before") GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after") GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image") GK_ATOM(mozquote, "_moz_quote") +GK_ATOM(mozsignature, "moz-signature") GK_ATOM(_moz_is_glyph, "-moz-is-glyph") GK_ATOM(_moz_original_size, "_moz_original_size") GK_ATOM(_moz_target, "_moz_target") diff --git a/content/canvas/src/WebGLContextReporter.cpp b/content/canvas/src/WebGLContextReporter.cpp index 3f8d79f1bd39..c2da4d8d5b4d 100644 --- a/content/canvas/src/WebGLContextReporter.cpp +++ b/content/canvas/src/WebGLContextReporter.cpp @@ -26,14 +26,6 @@ WebGLMemoryMultiReporter::GetName(nsACString &aName) return NS_OK; } -NS_IMETHODIMP -WebGLMemoryMultiReporter::GetExplicitNonHeap(int64_t *aAmount) -{ - // WebGLMemoryMultiReporterWrapper has no KIND_NONHEAP measurements. - *aAmount = 0; - return NS_OK; -} - NS_IMETHODIMP WebGLMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, nsISupports* aClosure) diff --git a/content/media/webaudio/AudioContext.cpp b/content/media/webaudio/AudioContext.cpp index 078f7715c8a4..c4fec440dc8f 100644 --- a/content/media/webaudio/AudioContext.cpp +++ b/content/media/webaudio/AudioContext.cpp @@ -247,5 +247,19 @@ AudioContext::Resume() } } +JSContext* +AudioContext::GetJSContext() const +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr scriptGlobal = + do_QueryInterface(GetParentObject()); + nsIScriptContext* scriptContext = scriptGlobal->GetContext(); + if (!scriptContext) { + return nullptr; + } + return scriptContext->GetNativeContext(); +} + } } diff --git a/content/media/webaudio/AudioContext.h b/content/media/webaudio/AudioContext.h index 4ca8b006c09d..f3069b6de1e0 100644 --- a/content/media/webaudio/AudioContext.h +++ b/content/media/webaudio/AudioContext.h @@ -141,6 +141,8 @@ public: void UnregisterPannerNode(PannerNode* aNode); void UpdatePannerSource(); + JSContext* GetJSContext() const; + private: void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob); diff --git a/content/media/webaudio/MediaBufferDecoder.cpp b/content/media/webaudio/MediaBufferDecoder.cpp index a850178623f6..9dd3d522e55a 100644 --- a/content/media/webaudio/MediaBufferDecoder.cpp +++ b/content/media/webaudio/MediaBufferDecoder.cpp @@ -97,7 +97,7 @@ private: // GetReentrantMonitor correctly. ReentrantMonitor mReentrantMonitor; nsCOMPtr mDecodeThread; - nsAutoPtr mResource; + nsRefPtr mResource; }; NS_IMPL_THREADSAFE_ISUPPORTS0(BufferDecoder) @@ -389,7 +389,7 @@ MediaDecodeTask::CreateReader() { MOZ_ASSERT(NS_IsMainThread()); - BufferMediaResource* resource = + nsRefPtr resource = new BufferMediaResource(static_cast (mBuffer), mLength, mPrincipal, mContentType); @@ -418,10 +418,10 @@ MediaDecodeTask::Decode() { MOZ_ASSERT(!NS_IsMainThread()); - mDecoderReader->OnDecodeThreadStart(); - mBufferDecoder->BeginDecoding(NS_GetCurrentThread()); + mDecoderReader->OnDecodeThreadStart(); + VideoInfo videoInfo; nsAutoPtr tags; nsresult rv = mDecoderReader->ReadMetadata(&videoInfo, getter_Transfers(tags)); @@ -591,7 +591,7 @@ WebAudioDecodeJob::FinalizeBufferData() MOZ_ASSERT(mOutput); MOZ_ASSERT(mChannels == mChannelBuffers.Length()); - AutoPushJSContext cx(GetJSContext()); + AutoPushJSContext cx(mContext->GetJSContext()); if (!cx) { return false; } @@ -603,20 +603,6 @@ WebAudioDecodeJob::FinalizeBufferData() return true; } -JSContext* -WebAudioDecodeJob::GetJSContext() const -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr scriptGlobal = - do_QueryInterface(mContext->GetParentObject()); - nsIScriptContext* scriptContext = scriptGlobal->GetContext(); - if (!scriptContext) { - return nullptr; - } - return scriptContext->GetNativeContext(); -} - bool WebAudioDecodeJob::AllocateBuffer() { @@ -624,7 +610,7 @@ WebAudioDecodeJob::AllocateBuffer() MOZ_ASSERT(NS_IsMainThread()); // First, get a JSContext - AutoPushJSContext cx(GetJSContext()); + AutoPushJSContext cx(mContext->GetJSContext()); if (!cx) { return false; } diff --git a/content/media/webaudio/MediaBufferDecoder.h b/content/media/webaudio/MediaBufferDecoder.h index ed214208344d..75832008806f 100644 --- a/content/media/webaudio/MediaBufferDecoder.h +++ b/content/media/webaudio/MediaBufferDecoder.h @@ -50,7 +50,6 @@ struct WebAudioDecodeJob void OnFailure(ErrorCode aErrorCode); bool AllocateBuffer(); - JSContext* GetJSContext() const; bool FinalizeBufferData(); nsCString mContentType; diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index c2e48f8fd846..e5ff15be2741 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -101,7 +101,8 @@ nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName, JSCLASS_NEW_RESOLVE | // Our one reserved slot holds the relevant nsXBLPrototypeBinding JSCLASS_HAS_RESERVED_SLOTS(1); - addProperty = delProperty = getProperty = ::JS_PropertyStub; + addProperty = getProperty = ::JS_PropertyStub; + delProperty = ::JS_DeletePropertyStub; setProperty = ::JS_StrictPropertyStub; enumerate = XBLEnumerate; resolve = JS_ResolveStub; diff --git a/content/xbl/src/nsXBLDocumentInfo.cpp b/content/xbl/src/nsXBLDocumentInfo.cpp index 16cca7e11e47..fef1da79af36 100644 --- a/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/content/xbl/src/nsXBLDocumentInfo.cpp @@ -173,7 +173,7 @@ JSClass nsXBLDocGlobalObject::gSharedGlobalClass = { "nsXBLPrototypeScript compilation scope", JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0), - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, nsXBLDocGlobalObject_getProperty, nsXBLDocGlobalObject_setProperty, JS_EnumerateStub, nsXBLDocGlobalObject_resolve, JS_ConvertStub, nsXBLDocGlobalObject_finalize, diff --git a/content/xul/document/src/nsXULPrototypeDocument.cpp b/content/xul/document/src/nsXULPrototypeDocument.cpp index 8a1bd0500311..a3b04196caac 100644 --- a/content/xul/document/src/nsXULPrototypeDocument.cpp +++ b/content/xul/document/src/nsXULPrototypeDocument.cpp @@ -114,7 +114,7 @@ JSClass nsXULPDGlobalObject::gSharedGlobalClass = { "nsXULPrototypeScript compilation scope", JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, nsXULPDGlobalObject_resolve, JS_ConvertStub, nsXULPDGlobalObject_finalize, nullptr, nullptr, nullptr, nullptr, nullptr diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index ebe23a56adc0..3a7a3c3cf3fb 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1386,7 +1386,7 @@ NS_INTERFACE_MAP_END static JSClass sDOMConstructorProtoClass = { "DOM Constructor.prototype", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr }; @@ -2681,8 +2681,7 @@ nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMClassInfo::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, - bool *_retval) + JSObject *obj, jsid id, bool *_retval) { NS_WARNING("nsDOMClassInfo::DelProperty Don't call me!"); @@ -3176,7 +3175,7 @@ static JSClass sGlobalScopePolluterClass = { "Global Scope Polluter", JSCLASS_NEW_RESOLVE, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, nsWindowSH::GlobalScopePolluterGetProperty, JS_StrictPropertyStub, JS_EnumerateStub, @@ -6316,7 +6315,7 @@ static JSClass sHTMLDocumentAllClass = { JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE | JSCLASS_EMULATES_UNDEFINED | JSCLASS_HAS_RESERVED_SLOTS(1), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ nsHTMLDocumentSH::DocumentAllGetProperty, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -6332,7 +6331,7 @@ static JSClass sHTMLDocumentAllHelperClass = { "HTML document.all helper class", JSCLASS_NEW_RESOLVE, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ nsHTMLDocumentSH::DocumentAllHelperGetProperty, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -6345,7 +6344,7 @@ static JSClass sHTMLDocumentAllTagsClass = { "HTML document.all.tags class", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_PRIVATE_IS_NSISUPPORTS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -7429,7 +7428,7 @@ nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, - jsval *vp, bool *_retval) + bool *_retval) { nsCOMPtr storage(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); @@ -7441,11 +7440,12 @@ nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper, NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED); nsresult rv = storage->RemoveItem(keyStr); - if (NS_SUCCEEDED(rv)) { - rv = NS_SUCCESS_I_DID_SOMETHING; + if (NS_FAILED(rv)) { + return rv; } - return rv; + *_retval = true; + return NS_SUCCESS_I_DID_SOMETHING; } diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index bb16a11f48fd..a4cdc6adb246 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -1041,7 +1041,7 @@ protected: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, jsval *vp, bool *_retval); NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsid id, jsval *vp, bool *_retval); + JSObject *obj, jsid id, bool *_retval); NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, uint32_t enum_op, jsval *statep, jsid *idp, bool *_retval); diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index 84b9ea08cbe6..6fe4cc7accb4 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -410,14 +410,6 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb, return NS_OK; } -NS_IMETHODIMP -nsWindowMemoryReporter::GetExplicitNonHeap(int64_t* aAmount) -{ - // This reporter only measures heap memory, so we don't need to report any - // bytes for it. However, the JS multi-reporter needs to be invoked. - return xpc::JSMemoryMultiReporter::GetExplicitNonHeap(aAmount); -} - uint32_t nsWindowMemoryReporter::GetGhostTimeout() { @@ -668,14 +660,6 @@ GhostURLsReporter::GetName(nsACString& aName) return NS_OK; } -NS_IMETHODIMP -nsWindowMemoryReporter:: -GhostURLsReporter::GetExplicitNonHeap(int64_t* aOut) -{ - *aOut = 0; - return NS_OK; -} - struct ReportGhostWindowsEnumeratorData { nsIMemoryMultiReporterCallback* callback; diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 8e3e027c1355..aca253ae9aea 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -174,7 +174,7 @@ DOMJSClass Class = { { "%s", %s, %s, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -223,7 +223,7 @@ class CGPrototypeJSClass(CGThing): "%sPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -277,7 +277,7 @@ static DOMIfaceAndProtoJSClass InterfaceObjectClass = { "Function", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE + %i), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 9519ba58b90d..2ab1060cd5d0 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -570,7 +570,7 @@ class ThreadLocalJSRuntime JSClass ThreadLocalJSRuntime::sGlobalClass = { "IndexedDBTransactionThreadGlobal", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; @@ -835,7 +835,7 @@ public: JSClass IDBObjectStore::sDummyPropJSClass = { "dummy", 0, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index f629afad7ca7..4f600ffe32e6 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -115,7 +115,7 @@ static JSBool NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); static JSBool -NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); +NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); static JSBool NPObjWrapper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, @@ -188,7 +188,7 @@ NPObjectMember_Trace(JSTracer *trc, JSObject *obj); static JSClass sNPObjectMemberClass = { "NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, NPObjectMember_Convert, NPObjectMember_Finalize, nullptr, NPObjectMember_Call, @@ -1197,7 +1197,7 @@ NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMut } static JSBool -NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) +NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded) { NPObject *npobj = GetNPObject(cx, obj); @@ -1217,12 +1217,14 @@ NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMut if (!ReportExceptionIfPending(cx)) return JS_FALSE; - if (!hasProperty) + if (!hasProperty) { + *succeeded = true; return JS_TRUE; + } } if (!npobj->_class->removeProperty(npobj, identifier)) - vp.set(JSVAL_FALSE); + *succeeded = false; return ReportExceptionIfPending(cx); } diff --git a/dom/workers/Events.cpp b/dom/workers/Events.cpp index 0fb2406ee4a1..8d62b3440a1a 100644 --- a/dom/workers/Events.cpp +++ b/dom/workers/Events.cpp @@ -331,7 +331,7 @@ private: JSClass _varname = { \ _name, \ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), \ - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize \ }; @@ -586,7 +586,7 @@ private: JSClass _varname = { \ _name, \ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), \ - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize \ }; @@ -772,7 +772,7 @@ private: JSClass _varname = { \ _name, \ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), \ - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize \ }; @@ -951,7 +951,7 @@ private: JSClass ProgressEvent::sClass = { "ProgressEvent", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; diff --git a/dom/workers/Exceptions.cpp b/dom/workers/Exceptions.cpp index 9766bb85c9d9..ed212f319a41 100644 --- a/dom/workers/Exceptions.cpp +++ b/dom/workers/Exceptions.cpp @@ -157,7 +157,7 @@ private: JSClass DOMException::sClass = { "DOMException", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; diff --git a/dom/workers/File.cpp b/dom/workers/File.cpp index 047c0ca61cdf..7e59e7e0776f 100644 --- a/dom/workers/File.cpp +++ b/dom/workers/File.cpp @@ -203,7 +203,7 @@ private: JSClass Blob::sClass = { "Blob", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; @@ -370,7 +370,7 @@ private: JSClass File::sClass = { "File", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; diff --git a/dom/workers/ImageData.cpp b/dom/workers/ImageData.cpp index 90fd6498a968..85d533fab0a2 100644 --- a/dom/workers/ImageData.cpp +++ b/dom/workers/ImageData.cpp @@ -135,7 +135,7 @@ private: JSClass ImageData::sClass = { "ImageData", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; diff --git a/dom/workers/Location.cpp b/dom/workers/Location.cpp index 21bfd098da76..772e8d4214e4 100644 --- a/dom/workers/Location.cpp +++ b/dom/workers/Location.cpp @@ -149,7 +149,7 @@ private: JSClass Location::sClass = { "WorkerLocation", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; diff --git a/dom/workers/Navigator.cpp b/dom/workers/Navigator.cpp index 3e898b84e811..69b45625e5aa 100644 --- a/dom/workers/Navigator.cpp +++ b/dom/workers/Navigator.cpp @@ -138,7 +138,7 @@ private: JSClass Navigator::sClass = { "WorkerNavigator", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize }; diff --git a/dom/workers/Worker.cpp b/dom/workers/Worker.cpp index 8abc5359fea9..387b3bdfcd8a 100644 --- a/dom/workers/Worker.cpp +++ b/dom/workers/Worker.cpp @@ -301,7 +301,7 @@ DOMJSClass Worker::sClass = { "Worker", JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IMPLEMENTS_BARRIERS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, NULL, NULL, NULL, NULL, Trace }, @@ -321,7 +321,7 @@ DOMIfaceAndProtoJSClass Worker::sProtoClass = { "Worker", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -464,7 +464,7 @@ DOMJSClass ChromeWorker::sClass = { { "ChromeWorker", JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IMPLEMENTS_BARRIERS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, NULL, NULL, NULL, NULL, Trace, }, @@ -484,7 +484,7 @@ DOMIfaceAndProtoJSClass ChromeWorker::sProtoClass = { "ChromeWorker", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index a84cd3751f9f..bac8d8dfcc0e 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -1774,8 +1774,7 @@ public: MutexAutoLock lock(mMutex); if (!mWorkerPrivate || - !mWorkerPrivate->BlockAndCollectRuntimeStats(/* aIsQuick = */ false, - &rtStats)) { + !mWorkerPrivate->BlockAndCollectRuntimeStats(&rtStats)) { // Returning NS_OK here will effectively report 0 memory. return NS_OK; } @@ -1785,24 +1784,6 @@ public: aCallback, aClosure); } - NS_IMETHOD - GetExplicitNonHeap(int64_t* aAmount) - { - AssertIsOnMainThread(); - - { - MutexAutoLock lock(mMutex); - - if (!mWorkerPrivate || - !mWorkerPrivate->BlockAndCollectRuntimeStats(/* aIsQuick = */ true, - aAmount)) { - *aAmount = 0; - } - } - - return NS_OK; - } - private: ~MemoryReporter() { } @@ -2940,11 +2921,11 @@ WorkerPrivate::ScheduleDeletion(bool aWasPending) } bool -WorkerPrivate::BlockAndCollectRuntimeStats(bool aIsQuick, void* aData) +WorkerPrivate::BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats) { AssertIsOnMainThread(); mMutex.AssertCurrentThreadOwns(); - NS_ASSERTION(aData, "Null data!"); + NS_ASSERTION(aRtStats, "Null RuntimeStats!"); NS_ASSERTION(!mMemoryReporterRunning, "How can we get reentered here?!"); @@ -2973,16 +2954,7 @@ WorkerPrivate::BlockAndCollectRuntimeStats(bool aIsQuick, void* aData) if (mMemoryReporter) { // Don't hold the lock while doing the actual report. MutexAutoUnlock unlock(mMutex); - - if (aIsQuick) { - *static_cast(aData) = - JS::GetExplicitNonHeapForRuntime(rt, JsWorkerMallocSizeOf); - succeeded = true; - } else { - succeeded = - JS::CollectRuntimeStats(rt, static_cast(aData), - nullptr); - } + succeeded = JS::CollectRuntimeStats(rt, aRtStats, nullptr); } NS_ASSERTION(mMemoryReporterRunning, "This isn't possible!"); diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 1d9c8b5acbca..e07490964566 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -41,6 +41,7 @@ class nsIURI; class nsPIDOMWindow; class nsITimer; class nsIXPCScriptNotify; +namespace JS { class RuntimeStats; } BEGIN_WORKERS_NAMESPACE @@ -821,7 +822,7 @@ public: ScheduleDeletion(bool aWasPending); bool - BlockAndCollectRuntimeStats(bool aIsQuick, void* aData); + BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats); bool XHRParamsAllowed() const diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index e13a1142c8f8..81036b51677f 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -612,7 +612,7 @@ private: JSClass WorkerGlobalScope::sClass = { "WorkerGlobalScope", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; @@ -878,7 +878,7 @@ DOMJSClass DedicatedWorkerGlobalScope::sClass = { "DedicatedWorkerGlobalScope", JSCLASS_DOM_GLOBAL | JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3) | JSCLASS_NEW_RESOLVE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, reinterpret_cast(Resolve), JS_ConvertStub, Finalize, NULL, NULL, NULL, NULL, Trace }, @@ -898,7 +898,7 @@ DOMIfaceAndProtoJSClass DedicatedWorkerGlobalScope::sProtoClass = { "DedicatedWorkerGlobalScope", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/editor/composer/src/nsComposeTxtSrvFilter.cpp b/editor/composer/src/nsComposeTxtSrvFilter.cpp index 84577de2ec5c..bf3049601d1d 100644 --- a/editor/composer/src/nsComposeTxtSrvFilter.cpp +++ b/editor/composer/src/nsComposeTxtSrvFilter.cpp @@ -3,11 +3,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsCaseTreatment.h" #include "nsComposeTxtSrvFilter.h" #include "nsError.h" // for NS_OK #include "nsIContent.h" // for nsIContent -#include "nsID.h" #include "nsIDOMNode.h" // for nsIDOMNode #include "nsINameSpaceManager.h" // for kNameSpaceID_None #include "nsLiteralString.h" // for NS_LITERAL_STRING @@ -16,25 +14,11 @@ nsComposeTxtSrvFilter::nsComposeTxtSrvFilter() : mIsForMail(false) { - - mBlockQuoteAtom = do_GetAtom("blockquote"); - mSpanAtom = do_GetAtom("span"); - mTableAtom = do_GetAtom("table"); - mMozQuoteAtom = do_GetAtom("_moz_quote"); - mClassAtom = do_GetAtom("class"); - mTypeAtom = do_GetAtom("type"); - mScriptAtom = do_GetAtom("script"); - mTextAreaAtom = do_GetAtom("textarea"); - mSelectAreaAtom = do_GetAtom("select"); - mMapAtom = do_GetAtom("map"); - mCiteAtom = do_GetAtom("cite"); - mTrueAtom = do_GetAtom("true"); - mMozSignatureAtom= do_GetAtom("moz-signature"); } NS_IMPL_ISUPPORTS1(nsComposeTxtSrvFilter, nsITextServicesFilter) -NS_IMETHODIMP +NS_IMETHODIMP nsComposeTxtSrvFilter::Skip(nsIDOMNode* aNode, bool *_retval) { *_retval = false; @@ -45,32 +29,32 @@ nsComposeTxtSrvFilter::Skip(nsIDOMNode* aNode, bool *_retval) nsCOMPtr content(do_QueryInterface(aNode)); if (content) { nsIAtom *tag = content->Tag(); - if (tag == mBlockQuoteAtom) { + if (tag == nsGkAtoms::blockquote) { if (mIsForMail) { - *_retval = content->AttrValueIs(kNameSpaceID_None, mTypeAtom, - mCiteAtom, eIgnoreCase); + *_retval = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::cite, eIgnoreCase); } - } else if (tag == mSpanAtom) { + } else if (tag == nsGkAtoms::span) { if (mIsForMail) { - *_retval = content->AttrValueIs(kNameSpaceID_None, mMozQuoteAtom, - mTrueAtom, eIgnoreCase); + *_retval = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozquote, + nsGkAtoms::_true, eIgnoreCase); if (!*_retval) { - *_retval = content->AttrValueIs(kNameSpaceID_None, mClassAtom, - mMozSignatureAtom, eCaseMatters); + *_retval = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::_class, + nsGkAtoms::mozsignature, eCaseMatters); } - } - } else if (tag == mScriptAtom || - tag == mTextAreaAtom || - tag == mSelectAreaAtom || - tag == mMapAtom) { + } + } else if (tag == nsGkAtoms::script || + tag == nsGkAtoms::textarea || + tag == nsGkAtoms::select || + tag == nsGkAtoms::map) { *_retval = true; - } else if (tag == mTableAtom) { + } else if (tag == nsGkAtoms::table) { if (mIsForMail) { *_retval = - content->AttrValueIs(kNameSpaceID_None, mClassAtom, + content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::_class, NS_LITERAL_STRING("moz-email-headers-table"), eCaseMatters); - } + } } } diff --git a/editor/composer/src/nsComposeTxtSrvFilter.h b/editor/composer/src/nsComposeTxtSrvFilter.h index 90cd4933c210..6a27ca9b0cad 100644 --- a/editor/composer/src/nsComposeTxtSrvFilter.h +++ b/editor/composer/src/nsComposeTxtSrvFilter.h @@ -6,8 +6,6 @@ #ifndef nsComposeTxtSrvFilter_h__ #define nsComposeTxtSrvFilter_h__ -#include "nsCOMPtr.h" // for nsCOMPtr -#include "nsIAtom.h" // for nsIAtom #include "nsISupportsImpl.h" // for NS_DECL_ISUPPORTS #include "nsITextServicesFilter.h" @@ -18,11 +16,10 @@ * This filter is used to skip over various form control nodes and * mail's cite nodes */ -class nsComposeTxtSrvFilter : public nsITextServicesFilter +class nsComposeTxtSrvFilter MOZ_FINAL : public nsITextServicesFilter { public: nsComposeTxtSrvFilter(); - virtual ~nsComposeTxtSrvFilter() {} // nsISupports interface... NS_DECL_ISUPPORTS @@ -33,21 +30,8 @@ public: // Helper - Intializer void Init(bool aIsForMail) { mIsForMail = aIsForMail; } -protected: +private: bool mIsForMail; - nsCOMPtr mBlockQuoteAtom; - nsCOMPtr mSpanAtom; // mail plain text quotes are wrapped in span tags - nsCOMPtr mMozQuoteAtom; // _moz_quote_ - nsCOMPtr mTableAtom; - nsCOMPtr mClassAtom; - nsCOMPtr mTypeAtom; - nsCOMPtr mScriptAtom; - nsCOMPtr mTextAreaAtom; - nsCOMPtr mSelectAreaAtom; - nsCOMPtr mMapAtom; - nsCOMPtr mCiteAtom; - nsCOMPtr mTrueAtom; - nsCOMPtr mMozSignatureAtom; }; #define NS_COMPOSERTXTSRVFILTER_CID \ diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 68a4bb08d76a..2bc2ce65cbb7 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -162,7 +162,6 @@ nsHTMLEditor::HideAnonymousEditingUIs() NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLEditor, nsPlaintextEditor) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTypeInState) NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheets) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextServices) tmp->HideAnonymousEditingUIs(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -170,7 +169,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLEditor, nsPlaintextEditor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTypeInState) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextServices) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopLeftHandle) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopHandle) diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index a6d9bf1952d7..9b46fe24432b 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -14,7 +14,6 @@ #include "nsITableEditor.h" #include "nsIEditorMailSupport.h" #include "nsIEditorStyleSheets.h" -#include "nsITextServicesDocument.h" #include "nsEditor.h" #include "nsIDOMElement.h" @@ -766,9 +765,6 @@ protected: // an array for holding default style settings nsTArray mDefaultStyles; - // for real-time spelling - nsCOMPtr mTextServices; - protected: /* ANONYMOUS UTILS */ diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp index 0c995b68c26b..431188dbaa07 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -481,9 +481,8 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(mozInlineSpellChecker) NS_IMPL_CYCLE_COLLECTING_RELEASE(mozInlineSpellChecker) -NS_IMPL_CYCLE_COLLECTION_4(mozInlineSpellChecker, +NS_IMPL_CYCLE_COLLECTION_3(mozInlineSpellChecker, mSpellCheck, - mTextServicesDocument, mTreeWalker, mCurrentSelectionAnchorNode) @@ -675,16 +674,6 @@ mozInlineSpellChecker::SetEnableRealTimeSpell(bool aEnabled) res = spellchecker->InitSpellChecker(editor, false); NS_ENSURE_SUCCESS(res, res); - nsCOMPtr tsDoc = do_CreateInstance("@mozilla.org/textservices/textservicesdocument;1", &res); - NS_ENSURE_SUCCESS(res, res); - - res = tsDoc->SetFilter(filter); - NS_ENSURE_SUCCESS(res, res); - - res = tsDoc->InitWithEditor(editor); - NS_ENSURE_SUCCESS(res, res); - - mTextServicesDocument = tsDoc; mSpellCheck = spellchecker; // spell checking is enabled, register our event listeners to track navigation diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.h b/extensions/spellcheck/src/mozInlineSpellChecker.h index 374efe644443..dcdb06c4bc56 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.h +++ b/extensions/spellcheck/src/mozInlineSpellChecker.h @@ -11,7 +11,6 @@ #include "nsIEditorSpellCheck.h" #include "nsIEditActionListener.h" #include "nsIInlineSpellChecker.h" -#include "nsITextServicesDocument.h" #include "nsIDOMTreeWalker.h" #include "nsWeakReference.h" #include "nsEditor.h" @@ -130,7 +129,6 @@ private: nsWeakPtr mEditor; nsCOMPtr mSpellCheck; - nsCOMPtr mTextServicesDocument; nsCOMPtr mTreeWalker; nsCOMPtr mConverter; diff --git a/gfx/layers/basic/BasicCanvasLayer.h b/gfx/layers/basic/BasicCanvasLayer.h index 3e6fbe205791..d4f31f1b09ee 100644 --- a/gfx/layers/basic/BasicCanvasLayer.h +++ b/gfx/layers/basic/BasicCanvasLayer.h @@ -104,7 +104,6 @@ class BasicShadowableCanvasLayer : public BasicCanvasLayer, public: BasicShadowableCanvasLayer(BasicShadowLayerManager* aManager) : BasicCanvasLayer(aManager), - mBufferIsOpaque(false), mCanvasClient(nullptr) { MOZ_COUNT_CTOR(BasicShadowableCanvasLayer); @@ -154,7 +153,6 @@ private: return BUFFER_IMAGE_SINGLE; } - bool mBufferIsOpaque; RefPtr mCanvasClient; }; diff --git a/gfx/layers/basic/BasicThebesLayer.cpp b/gfx/layers/basic/BasicThebesLayer.cpp index 4451bcdf57d6..b88e8f4a149b 100644 --- a/gfx/layers/basic/BasicThebesLayer.cpp +++ b/gfx/layers/basic/BasicThebesLayer.cpp @@ -278,11 +278,8 @@ BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext, void* aCallbackData) { ContentClientRemote* contentClientRemote = static_cast(mContentClient.get()); - if (HasShadow() && !mContentClient->GetIPDLActor()) { - mContentClient->Connect(); - BasicManager()->Attach(mContentClient, this); - } MOZ_ASSERT(contentClientRemote->GetIPDLActor() || !HasShadow()); + // NB: this just throws away the entire valid region if there are // too many rects. mValidRegion.SimplifyInward(8); diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 386cca665159..d3c60a7d8cf4 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -634,12 +634,6 @@ public: return NS_OK; } - - NS_IMETHOD GetExplicitNonHeap(int64_t *n) - { - *n = 0; // this reporter makes neither "explicit" non NONHEAP reports - return NS_OK; - } }; NS_IMPL_ISUPPORTS1(SurfaceMemoryReporter, nsIMemoryMultiReporter) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 875374599320..ccf93a5b6e14 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1137,14 +1137,6 @@ gfxFontCache::MemoryReporter::CollectReports return NS_OK; } -NS_IMETHODIMP -gfxFontCache::MemoryReporter::GetExplicitNonHeap(int64_t* aAmount) -{ - // This reporter only measures heap memory. - *aAmount = 0; - return NS_OK; -} - // Observer for the memory-pressure notification, to trigger // flushing of the shaped-word caches class MemoryPressureObserver MOZ_FINAL : public nsIObserver, diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index afb2f9d517ab..7dd9935f45a0 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -120,14 +120,6 @@ gfxPlatformFontList::MemoryReporter::CollectReports return NS_OK; } -NS_IMETHODIMP -gfxPlatformFontList::MemoryReporter::GetExplicitNonHeap(int64_t* aAmount) -{ - // This reporter only measures heap memory. - *aAmount = 0; - return NS_OK; -} - gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) : mNeedFullnamePostscriptNames(aNeedFullnamePostscriptNames), mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 1ee71f336e40..6d913f07ffa6 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -323,15 +323,6 @@ public: return NS_OK; } - - // nsIMemoryMultiReporter abstract method implementation - NS_IMETHOD - GetExplicitNonHeap(int64_t *aExplicitNonHeap) - { - // This reporter doesn't do any non-heap measurements. - *aExplicitNonHeap = 0; - return NS_OK; - } }; NS_IMPL_ISUPPORTS1(GPUAdapterMultiReporter, nsIMemoryMultiReporter) #endif // ENABLE_GPU_MEM_REPORTER diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index b2e88bc9295e..5c9e5624241e 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -2674,9 +2674,6 @@ RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount) mDecoder->Write(aBuffer, aCount); mInDecoder = false; - if (!mDecoder) - return NS_ERROR_FAILURE; - CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError()); // Keep track of the total number of bytes written over the lifetime of the @@ -3278,7 +3275,6 @@ RasterImage::IsDecodeFinished() // Precondition mDecodingMutex.AssertCurrentThreadOwns(); NS_ABORT_IF_FALSE(mDecoder, "Can't call IsDecodeFinished() without decoder!"); - MOZ_ASSERT(mDecodeRequest); // The decode is complete if we got what we wanted. if (mDecoder->IsSizeDecode()) { @@ -3288,11 +3284,12 @@ RasterImage::IsDecodeFinished() } else if (mDecoder->GetDecodeDone()) { return true; } - + // If the decoder returned because it needed a new frame and we haven't // written to it since then, the decoder may be storing data that it hasn't // decoded yet. - if (mDecoder->NeedsNewFrame() || mDecodeRequest->mAllocatedNewFrame) { + if (mDecoder->NeedsNewFrame() || + (mDecodeRequest && mDecodeRequest->mAllocatedNewFrame)) { return false; } diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index db829310e18c..03a1cf4cdec9 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -150,17 +150,6 @@ public: return NS_OK; } - NS_IMETHOD GetExplicitNonHeap(int64_t *n) - { - size_t n2 = 0; - for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) { - mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryExplicitNonHeapSize, &n2); - mKnownLoaders[i]->mCache.EnumerateRead(EntryExplicitNonHeapSize, &n2); - } - *n = n2; - return NS_OK; - } - static int64_t GetImagesContentUsedUncompressed() { size_t n = 0; @@ -222,20 +211,6 @@ private: return PL_DHASH_NEXT; } - static PLDHashOperator EntryExplicitNonHeapSize(const nsACString&, - imgCacheEntry *entry, - void *userArg) - { - size_t *n = static_cast(userArg); - nsRefPtr req = entry->GetRequest(); - Image *image = static_cast(req->mImage.get()); - if (image) { - *n += image->NonHeapSizeOfDecoded(); - } - - return PL_DHASH_NEXT; - } - static PLDHashOperator EntryUsedUncompressedSize(const nsACString&, imgCacheEntry *entry, void *userArg) diff --git a/js/ipc/ObjectWrapperChild.cpp b/js/ipc/ObjectWrapperChild.cpp index 7c90e3612cb0..7eb823a5440f 100644 --- a/js/ipc/ObjectWrapperChild.cpp +++ b/js/ipc/ObjectWrapperChild.cpp @@ -400,7 +400,7 @@ static const JSClass sCPOW_NewEnumerateState_JSClass = { "CPOW NewEnumerate State", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(sNumNewEnumerateStateSlots), - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CPOW_NewEnumerateState_Finalize diff --git a/js/ipc/ObjectWrapperParent.cpp b/js/ipc/ObjectWrapperParent.cpp index 9a80c99e7690..61a607107328 100644 --- a/js/ipc/ObjectWrapperParent.cpp +++ b/js/ipc/ObjectWrapperParent.cpp @@ -274,6 +274,43 @@ ObjectWrapperParent::jsval_from_JSVariant(JSContext* cx, const JSVariant& from, } } +/*static*/ bool +ObjectWrapperParent::boolean_from_JSVariant(JSContext* cx, const JSVariant& from, + JSBool* to) +{ + switch (from.type()) { + case JSVariant::Tvoid_t: + *to = false; + return true; + case JSVariant::TPObjectWrapperParent: { + JS::Rooted v(cx); + if (!jsval_from_PObjectWrapperParent(cx, from.get_PObjectWrapperParent(), v.address())) + return false; + *to = JS::ToBoolean(v); + return true; + } + case JSVariant::TnsString: + { + JSString* str = JS_NewUCStringCopyZ(cx, from.get_nsString().BeginReading()); + if (!str) + return false; + *to = JS::ToBoolean(JS::StringValue(str)); + return true; + } + case JSVariant::Tint: + *to = from.get_int() != 0; + return true; + case JSVariant::Tdouble: + *to = JS::ToBoolean(JS::DoubleValue(from.get_double())); + return true; + case JSVariant::Tbool: + *to = from.get_bool(); + return true; + default: + return false; + } +} + /*static*/ bool ObjectWrapperParent:: JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to) @@ -432,7 +469,7 @@ ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandl /*static*/ JSBool ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSMutableHandleValue vp) + JSBool *succeeded) { CPOW_LOG(("Calling CPOW_DelProperty (%s)...", JSVAL_TO_CSTR(cx, id))); @@ -454,7 +491,7 @@ ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandl self->CallDelProperty(in_id, aco.StatusPtr(), &out_v) && aco.Ok() && - jsval_from_JSVariant(cx, out_v, vp.address())); + boolean_from_JSVariant(cx, out_v, succeeded)); } JSBool @@ -691,4 +728,4 @@ ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JSMutab self->CallHasInstance(in_v, aco.StatusPtr(), bp) && aco.Ok()); -} \ No newline at end of file +} diff --git a/js/ipc/ObjectWrapperParent.h b/js/ipc/ObjectWrapperParent.h index a389b52956d9..89b2e5139a70 100644 --- a/js/ipc/ObjectWrapperParent.h +++ b/js/ipc/ObjectWrapperParent.h @@ -63,7 +63,7 @@ private: CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); static JSBool - CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); + CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); static JSBool CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); @@ -100,6 +100,8 @@ private: static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to); static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from, jsval* to); + static bool boolean_from_JSVariant(JSContext* cx, const JSVariant& from, + JSBool* to); static bool JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to); static bool diff --git a/js/jsd/jsd_high.cpp b/js/jsd/jsd_high.cpp index 3a7bea446e36..9ba321cd5e1f 100644 --- a/js/jsd/jsd_high.cpp +++ b/js/jsd/jsd_high.cpp @@ -52,7 +52,7 @@ CreateJSDGlobal(JSContext *cx, JSClass *clasp); static JSClass global_class = { "JSDGlobal", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, global_finalize }; diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 14cf88ec4c60..f14dc73912cf 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -444,9 +444,6 @@ class ObjectPrivateVisitor extern JS_PUBLIC_API(bool) CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv); -extern JS_PUBLIC_API(int64_t) -GetExplicitNonHeapForRuntime(JSRuntime *rt, JSMallocSizeOfFun mallocSizeOf); - extern JS_PUBLIC_API(size_t) SystemCompartmentCount(JSRuntime *rt); diff --git a/js/src/build/autoconf/android.m4 b/js/src/build/autoconf/android.m4 index 2144d6e9f980..a3ceccd906d0 100644 --- a/js/src/build/autoconf/android.m4 +++ b/js/src/build/autoconf/android.m4 @@ -254,7 +254,7 @@ if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then fi STLPORT_SOURCES="$android_ndk/sources/cxx-stl/stlport" STLPORT_CPPFLAGS="-I$_objdir/build/stlport -I$android_ndk/sources/cxx-stl/stlport/stlport" - STLPORT_LIBS="-lstlport_static" + STLPORT_LIBS="-lstlport_static -static-libstdc++" elif test "$target" != "arm-android-eabi"; then dnl fail if we're not building with NDKr4 AC_MSG_ERROR([Couldn't find path to stlport in the android ndk]) diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index d3463125da23..6e22cc76f358 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -582,7 +582,7 @@ static Class CollatorClass = { js_Object_str, JSCLASS_HAS_RESERVED_SLOTS(COLLATOR_SLOTS_COUNT), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1060,7 +1060,7 @@ static Class NumberFormatClass = { js_Object_str, JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1509,7 +1509,7 @@ static Class DateTimeFormatClass = { js_Object_str, JSCLASS_HAS_RESERVED_SLOTS(DATE_TIME_FORMAT_SLOTS_COUNT), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1985,7 +1985,7 @@ Class js::IntlClass = { js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Intl), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 1f6258f49bcc..08100842e2a9 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -873,7 +873,7 @@ Class js::MapIteratorClass = { JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1013,7 +1013,7 @@ Class MapObject::class_ = { JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_Map), JS_PropertyStub, // addProperty - JS_PropertyStub, // delProperty + JS_DeletePropertyStub, // delProperty JS_PropertyStub, // getProperty JS_StrictPropertyStub, // setProperty JS_EnumerateStub, @@ -1446,7 +1446,7 @@ Class js::SetIteratorClass = { JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1556,7 +1556,7 @@ Class SetObject::class_ = { JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_Set), JS_PropertyStub, // addProperty - JS_PropertyStub, // delProperty + JS_DeletePropertyStub, // delProperty JS_PropertyStub, // getProperty JS_StrictPropertyStub, // setProperty JS_EnumerateStub, diff --git a/js/src/builtin/Module.cpp b/js/src/builtin/Module.cpp index d70ec483e11e..2aaf96508585 100644 --- a/js/src/builtin/Module.cpp +++ b/js/src/builtin/Module.cpp @@ -7,7 +7,7 @@ Class js::ModuleClass = { "Module", JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/builtin/ParallelArray.cpp b/js/src/builtin/ParallelArray.cpp index c98771d047e4..04bcae9f3af5 100644 --- a/js/src/builtin/ParallelArray.cpp +++ b/js/src/builtin/ParallelArray.cpp @@ -53,7 +53,7 @@ Class ParallelArrayObject::protoClass = { "ParallelArray", JSCLASS_HAS_CACHED_PROTO(JSProto_ParallelArray), JS_PropertyStub, // addProperty - JS_PropertyStub, // delProperty + JS_DeletePropertyStub, // delProperty JS_PropertyStub, // getProperty JS_StrictPropertyStub, // setProperty JS_EnumerateStub, @@ -65,7 +65,7 @@ Class ParallelArrayObject::class_ = { "ParallelArray", JSCLASS_HAS_CACHED_PROTO(JSProto_ParallelArray), JS_PropertyStub, // addProperty - JS_PropertyStub, // delProperty + JS_DeletePropertyStub, // delProperty JS_PropertyStub, // getProperty JS_StrictPropertyStub, // setProperty JS_EnumerateStub, diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index e5f65c3a221b..9f9a57adf906 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -750,7 +750,7 @@ finalize_counter_finalize(JSFreeOp *fop, JSObject *obj) static JSClass FinalizeCounterClass = { "FinalizeCounter", JSCLASS_IS_ANONYMOUS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 4b29ed0ed1e5..e7213fc80c9f 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -444,14 +444,14 @@ namespace UInt64 { static JSClass sCTypesGlobalClass = { "ctypes", JSCLASS_HAS_RESERVED_SLOTS(CTYPESGLOBAL_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; static JSClass sCABIClass = { "CABI", JSCLASS_HAS_RESERVED_SLOTS(CABI_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; @@ -461,7 +461,7 @@ static JSClass sCABIClass = { static JSClass sCTypeProtoClass = { "CType", JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::FinalizeProtoClass, NULL, ConstructAbstract, NULL, ConstructAbstract }; @@ -471,14 +471,14 @@ static JSClass sCTypeProtoClass = { static JSClass sCDataProtoClass = { "CData", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; static JSClass sCTypeClass = { "CType", JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CType::Finalize, NULL, CType::ConstructData, CType::HasInstance, CType::ConstructData, CType::Trace @@ -487,7 +487,7 @@ static JSClass sCTypeClass = { static JSClass sCDataClass = { "CData", JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS), - JS_PropertyStub, JS_PropertyStub, ArrayType::Getter, ArrayType::Setter, + JS_PropertyStub, JS_DeletePropertyStub, ArrayType::Getter, ArrayType::Setter, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CData::Finalize, NULL, FunctionType::Call, NULL, FunctionType::Call }; @@ -495,7 +495,7 @@ static JSClass sCDataClass = { static JSClass sCClosureClass = { "CClosure", JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CClosure::Finalize, NULL, NULL, NULL, NULL, CClosure::Trace }; @@ -506,7 +506,7 @@ static JSClass sCClosureClass = { static JSClass sCDataFinalizerProtoClass = { "CDataFinalizer", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; @@ -519,7 +519,7 @@ static JSClass sCDataFinalizerProtoClass = { static JSClass sCDataFinalizerClass = { "CDataFinalizer", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, CDataFinalizer::Finalize, }; @@ -679,28 +679,28 @@ static JSFunctionSpec sFunctionInstanceFunctions[] = { static JSClass sInt64ProtoClass = { "Int64", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; static JSClass sUInt64ProtoClass = { "UInt64", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; static JSClass sInt64Class = { "Int64", JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize }; static JSClass sUInt64Class = { "UInt64", JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Int64Base::Finalize }; diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp index f76221331c25..1c2f8ea7c5ff 100644 --- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -33,7 +33,7 @@ typedef Rooted RootedFlatString; static JSClass sLibraryClass = { "Library", JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize }; diff --git a/js/src/gdb/gdb-tests.cpp b/js/src/gdb/gdb-tests.cpp index a19ed1e4d2fd..a5ce25cf364d 100644 --- a/js/src/gdb/gdb-tests.cpp +++ b/js/src/gdb/gdb-tests.cpp @@ -13,7 +13,7 @@ using namespace JS; /* The class of the global object. */ JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index d268f1f922b8..b955bc5fd570 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -2286,7 +2286,7 @@ static Class AsmJSModuleClass = { JSCLASS_IS_ANONYMOUS | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(ASM_CODE_NUM_RESERVED_SLOTS), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index ef11dca01b66..e41193c06496 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -203,8 +203,7 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) RootedScript inlineScript(cx, target->nonLazyScript()); ExecutionMode executionMode = info().executionMode(); if (!CanIonCompile(inlineScript, executionMode)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to disable Ion compilation", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to disable Ion compilation"); return false; } @@ -213,8 +212,7 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) ion::IsBaselineEnabled(cx) && !inlineScript->hasBaselineScript()) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline target with no baseline jitcode", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline target with no baseline jitcode"); return false; } @@ -222,8 +220,7 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) IonBuilder *builder = callerBuilder_; while (builder) { if (builder->script() == inlineScript) { - IonSpew(IonSpew_Inlining, "%s:%d Not inlining recursive call", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Not inlining recursive call"); return false; } builder = builder->callerBuilder_; @@ -232,15 +229,12 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) RootedScript callerScript(cx, script()); if (!oracle->canEnterInlinedFunction(target)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to oracle veto %d", - inlineScript->filename(), inlineScript->lineno, - script()->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d", script()->lineno); return false; } if (!oracle->callReturnTypeSetMatches(callerScript, pc, target)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to return typeset mismatch", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to return typeset mismatch"); return false; } @@ -249,8 +243,7 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) // For constructing calls the typeset of caller should intersect the callee's typeset. // Except for the |this| type, because that is created during execution depending on target. if (!oracle->callArgsTypeSetIntersects(NULL, callInfo.argvType(), target)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to arguments typeset mismatch", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to arguments typeset mismatch"); return false; } } else if (JSOp(*pc) == JSOP_FUNAPPLY) { @@ -259,25 +252,18 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) // of fun.apply. Seeing a new type will only be noticed in the inlined call and // result in missed types in TI. if (!oracle->callArgsTypeSetMatches(callInfo.thisType(), callInfo.argvType(), target)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to arguments typeset mismatch", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to arguments typeset mismatch"); return false; } } else { // For normal calls the typeset of caller should intersect the callee's typeset. if (!oracle->callArgsTypeSetIntersects(callInfo.thisType(), callInfo.argvType(), target)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to arguments typeset mismatch", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to arguments typeset mismatch"); return false; } } - if (inlineScript->hasIonScript() && inlineScript->ionScript()->bailoutExpected()) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to known bailing script", - inlineScript->filename(), inlineScript->lineno); - return false; - } - + IonSpew(IonSpew_Inlining, "Inlining good to go!"); return true; } @@ -3060,12 +3046,6 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) // Accumulate return values. MIRGraphExits &exits = *inlineBuilder.graph().exitAccumulator(); - if (exits.length() == 0) { - // Inlining of functions that have no exit is not supported. - calleeScript->analysis()->setIonUninlineable(); - abortReason_ = AbortReason_Inlining; - return false; - } MDefinition *retvalDefn = patchInlinedReturns(thisCall, exits, returnBlock); if (!retvalDefn) return false; @@ -3246,17 +3226,24 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) // Heuristics! - IonBuilder *baseBuilder = this; - while (baseBuilder->callerBuilder_) - baseBuilder = baseBuilder->callerBuilder_; + // Cap the inlining depth. + if (IsSmallFunction(targetScript)) { + if (inliningDepth_ >= js_IonOptions.smallFunctionMaxInlineDepth) { + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding allowed inline depth", + targetScript->filename(), targetScript->lineno); + return false; + } + } else { + if (inliningDepth_ >= js_IonOptions.maxInlineDepth) { + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding allowed inline depth", + targetScript->filename(), targetScript->lineno); + return false; + } + } - // When caller is excessively large only inline small functions. - if (script()->length > js_IonOptions.inlineMaxTotalBytecodeLength && - !IsSmallFunction(targetScript)) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: caller excessively large.", - targetScript->filename(), targetScript->lineno); - return false; - } + // Always inline the empty script up to the inlining depth. + if (targetScript->length == 1) + return true; // Callee must not be excessively large. // This heuristic also applies to the callsite as a whole. @@ -3281,36 +3268,6 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) return false; } - // Cap the inlining depth. - uint32_t scriptMaxInlineDepth = targetScript->maxInlineDepth(); - uint32_t globalMaxInlineDepth = js_IonOptions.maxInlineDepth; - if (IsSmallFunction(targetScript)) - globalMaxInlineDepth = js_IonOptions.smallFunctionMaxInlineDepth; - - // Cap the global inline depth. - if (inliningDepth_ >= globalMaxInlineDepth) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding global inline depth", - targetScript->filename(), targetScript->lineno); - baseBuilder->script()->disableInlineDepthCheck(); - return false; - } - - // Cap on scripts inline depth. - if (inliningDepth_ >= scriptMaxInlineDepth) - { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding script inline depth.", - targetScript->filename(), targetScript->lineno); - return false; - } - - // Update scripts max inline depth - // I.e. make sure that all known scripts that get inlined by this script still get inlined. - if (!baseBuilder->script()->isInlineDepthCheckDisabled()) { - uint32_t updatedInlineDepth = globalMaxInlineDepth - inliningDepth_ - 1; - if (updatedInlineDepth < baseBuilder->script()->maxInlineDepth()) - baseBuilder->script()->setMaxInlineDepth(updatedInlineDepth); - } - return true; } diff --git a/js/src/ion/TypeOracle.cpp b/js/src/ion/TypeOracle.cpp index 35aa88e63e26..6e67e7956079 100644 --- a/js/src/ion/TypeOracle.cpp +++ b/js/src/ion/TypeOracle.cpp @@ -703,6 +703,12 @@ TypeInferenceOracle::canEnterInlinedFunction(RawFunction target) { RootedScript targetScript(cx, target->nonLazyScript()); + // Make sure empty script has type information, to allow inlining in more cases. + if (targetScript->length == 1) { + if (!targetScript->ensureRanInference(cx)) + return false; + } + if (!targetScript->hasAnalysis() || !targetScript->analysis()->ranInference() || !targetScript->analysis()->ranSSA()) diff --git a/js/src/ion/x64/Assembler-x64.h b/js/src/ion/x64/Assembler-x64.h index 680d24c4f741..379a88eea1ae 100644 --- a/js/src/ion/x64/Assembler-x64.h +++ b/js/src/ion/x64/Assembler-x64.h @@ -510,7 +510,16 @@ class Assembler : public AssemblerX86Shared } void mov(ImmWord word, const Register &dest) { - movq(word, dest); + // If the word value is in [0,UINT32_MAX], we can use the more compact + // movl instruction, which has a 32-bit immediate field which it + // zero-extends into the 64-bit register. + if (word.value <= UINT32_MAX) { + uint32_t value32 = static_cast(word.value); + Imm32 imm32(static_cast(value32)); + movl(imm32, dest); + } else { + movq(word, dest); + } } void mov(const Imm32 &imm32, const Register &dest) { movl(imm32, dest); diff --git a/js/src/ion/x64/MacroAssembler-x64.h b/js/src/ion/x64/MacroAssembler-x64.h index 186943bf95a5..6165a0c5fe60 100644 --- a/js/src/ion/x64/MacroAssembler-x64.h +++ b/js/src/ion/x64/MacroAssembler-x64.h @@ -79,7 +79,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared // X64 helpers. ///////////////////////////////////////////////////////////////// void call(ImmWord target) { - movq(target, rax); + mov(target, rax); call(rax); } @@ -166,7 +166,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared JS_ASSERT(dest.valueReg() != ScratchReg); if (payload != dest.valueReg()) movq(payload, dest.valueReg()); - movq(ImmShiftedTag(type), ScratchReg); + mov(ImmShiftedTag(type), ScratchReg); orq(Operand(ScratchReg), dest.valueReg()); } void pushValue(ValueOperand val) { @@ -207,7 +207,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared JS_ASSERT(src != dest); JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); - movq(ImmShiftedTag(tag), dest); + mov(ImmShiftedTag(tag), dest); #ifdef DEBUG if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { Label upper32BitsZeroed; @@ -344,7 +344,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void cmpPtr(const Register &lhs, const ImmWord rhs) { JS_ASSERT(lhs != ScratchReg); - movq(rhs, ScratchReg); + mov(rhs, ScratchReg); cmpq(lhs, ScratchReg); } void cmpPtr(const Register &lhs, const ImmGCPtr rhs) { @@ -357,7 +357,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared cmpq(lhs, ScratchReg); } void cmpPtr(const Operand &lhs, const ImmWord rhs) { - movq(rhs, ScratchReg); + mov(rhs, ScratchReg); cmpq(lhs, ScratchReg); } void cmpPtr(const Address &lhs, const ImmGCPtr rhs) { @@ -413,7 +413,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared } void addPtr(ImmWord imm, const Register &dest) { JS_ASSERT(dest != ScratchReg); - movq(imm, ScratchReg); + mov(imm, ScratchReg); addq(ScratchReg, dest); } void addPtr(const Address &src, const Register &dest) { @@ -430,14 +430,14 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared } void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { - movq(ImmWord(lhs.addr), ScratchReg); + mov(ImmWord(lhs.addr), ScratchReg); branch32(cond, Address(ScratchReg, 0), rhs, label); } // Specialization for AbsoluteAddress. void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) { JS_ASSERT(ptr != ScratchReg); - movq(ImmWord(addr.addr), ScratchReg); + mov(ImmWord(addr.addr), ScratchReg); branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label); } @@ -493,13 +493,13 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared movq(src, dest); } void movePtr(ImmWord imm, Register dest) { - movq(imm, dest); + mov(imm, dest); } void movePtr(ImmGCPtr imm, Register dest) { movq(imm, dest); } void loadPtr(const AbsoluteAddress &address, Register dest) { - movq(ImmWord(address.addr), ScratchReg); + mov(ImmWord(address.addr), ScratchReg); movq(Operand(ScratchReg, 0x0), dest); } void loadPtr(const Address &address, Register dest) { @@ -516,7 +516,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared shlq(Imm32(1), dest); } void storePtr(ImmWord imm, const Address &address) { - movq(imm, ScratchReg); + mov(imm, ScratchReg); movq(ScratchReg, Operand(address)); } void storePtr(ImmGCPtr imm, const Address &address) { @@ -530,7 +530,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared movq(src, dest); } void storePtr(const Register &src, const AbsoluteAddress &address) { - movq(ImmWord(address.addr), ScratchReg); + mov(ImmWord(address.addr), ScratchReg); movq(src, Operand(ScratchReg, 0x0)); } void rshiftPtr(Imm32 imm, Register dest) { @@ -871,7 +871,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared } pun; pun.d = d; if (!maybeInlineDouble(pun.u, dest)) { - movq(ImmWord(pun.u), ScratchReg); + mov(ImmWord(pun.u), ScratchReg); movqsd(ScratchReg, dest); } } diff --git a/js/src/ion/x64/Trampoline-x64.cpp b/js/src/ion/x64/Trampoline-x64.cpp index a8e1f6f86067..b25b253bed98 100644 --- a/js/src/ion/x64/Trampoline-x64.cpp +++ b/js/src/ion/x64/Trampoline-x64.cpp @@ -646,7 +646,7 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type) masm.PushRegsInMask(regs); JS_ASSERT(PreBarrierReg == rdx); - masm.movq(ImmWord(cx->runtime), rcx); + masm.mov(ImmWord(cx->runtime), rcx); masm.setupUnalignedABICall(2, rax); masm.passABIArg(rcx); diff --git a/js/src/jit-test/tests/basic/bug821850.js b/js/src/jit-test/tests/basic/bug821850.js index 7c7e45a4fff7..fb0819c7b661 100644 --- a/js/src/jit-test/tests/basic/bug821850.js +++ b/js/src/jit-test/tests/basic/bug821850.js @@ -6,4 +6,4 @@ assertThrowsInstanceOf(function() {"use strict"; delete m.p;}, TypeError); x = new Proxy(m, {}) assertEq(x.p, 3); -assertEq((function fun() {"use strict"; return delete x.p; })(), false); +assertThrowsInstanceOf(function fun() {"use strict"; return delete x.p; }, TypeError); diff --git a/js/src/jit-test/tests/basic/delete-non-config.js b/js/src/jit-test/tests/basic/delete-non-config.js index afc7631007c0..da6020cad89b 100644 --- a/js/src/jit-test/tests/basic/delete-non-config.js +++ b/js/src/jit-test/tests/basic/delete-non-config.js @@ -1,5 +1,4 @@ var a = [0,1,2,3,4,5,6,7,8,9,10]; for (var i = 0; i < 10; i++) - delete a.length; + assertEq(delete a.length, false); assertEq(delete a.length, false); - diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index 64eec6de4443..0e5312f58ce2 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -77,7 +77,7 @@ ScriptAnalysis::addJump(JSContext *cx, unsigned offset, if (offset < *currentOffset) { /* Scripts containing loops are never inlined. */ - isJaegerInlineable = false; + isJaegerInlineable = isIonInlineable = false; hasLoops_ = true; if (code->analyzed) { diff --git a/js/src/jsapi-tests/testAddPropertyPropcache.cpp b/js/src/jsapi-tests/testAddPropertyPropcache.cpp index be190df1824c..8c6979e38a39 100644 --- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp +++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp @@ -24,7 +24,7 @@ JSClass addPropertyClass = { "AddPropertyTester", 0, addProperty, - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp index 1ccc9430b20a..6dec466c4cd3 100644 --- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp +++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp @@ -10,7 +10,7 @@ static JSClass CustomClass = { "CustomClass", JSCLASS_HAS_RESERVED_SLOTS(1), JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, diff --git a/js/src/jsapi-tests/testChromeBuffer.cpp b/js/src/jsapi-tests/testChromeBuffer.cpp index d476d797b3d9..2ea62f7c33ea 100644 --- a/js/src/jsapi-tests/testChromeBuffer.cpp +++ b/js/src/jsapi-tests/testChromeBuffer.cpp @@ -12,7 +12,7 @@ JSClass global_class = { "global", JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, diff --git a/js/src/jsapi-tests/testClassGetter.cpp b/js/src/jsapi-tests/testClassGetter.cpp index 420ef24c4346..86c3229afce7 100644 --- a/js/src/jsapi-tests/testClassGetter.cpp +++ b/js/src/jsapi-tests/testClassGetter.cpp @@ -27,7 +27,7 @@ static JSClass ptestClass = { JSCLASS_HAS_PRIVATE, JS_PropertyStub, // add - JS_PropertyStub, // delete + JS_DeletePropertyStub, // delete test_prop_get, // get JS_StrictPropertyStub, // set JS_EnumerateStub, diff --git a/js/src/jsapi-tests/testCustomIterator.cpp b/js/src/jsapi-tests/testCustomIterator.cpp index e1f628fc86e4..3c850811831e 100644 --- a/js/src/jsapi-tests/testCustomIterator.cpp +++ b/js/src/jsapi-tests/testCustomIterator.cpp @@ -32,7 +32,7 @@ js::Class HasCustomIterClass = { "HasCustomIter", 0, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index 692ca846d5b1..65edab7c0ebc 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -41,7 +41,7 @@ static JSClass DocumentAllClass = { "DocumentAll", JSCLASS_EMULATES_UNDEFINED, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, @@ -78,7 +78,7 @@ document_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flag static JSClass document_class = { "document", JSCLASS_NEW_RESOLVE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, (JSResolveOp) document_resolve, JS_ConvertStub }; diff --git a/js/src/jsapi-tests/testNewObject.cpp b/js/src/jsapi-tests/testNewObject.cpp index 94b8607bb1db..5a97aa72e4ad 100644 --- a/js/src/jsapi-tests/testNewObject.cpp +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -95,7 +95,7 @@ BEGIN_TEST(testNewObject_1) static JSClass cls = { "testNewObject_1", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, NULL, NULL, NULL, constructHook }; diff --git a/js/src/jsapi-tests/testObjectEmulatingUndefined.cpp b/js/src/jsapi-tests/testObjectEmulatingUndefined.cpp index 0ac5243a4b50..af5212a1b549 100644 --- a/js/src/jsapi-tests/testObjectEmulatingUndefined.cpp +++ b/js/src/jsapi-tests/testObjectEmulatingUndefined.cpp @@ -8,7 +8,7 @@ static JSClass ObjectEmulatingUndefinedClass = { "ObjectEmulatingUndefined", JSCLASS_EMULATES_UNDEFINED, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, diff --git a/js/src/jsapi-tests/testOps.cpp b/js/src/jsapi-tests/testOps.cpp index 648493be1df0..e0f7d8fa68ed 100644 --- a/js/src/jsapi-tests/testOps.cpp +++ b/js/src/jsapi-tests/testOps.cpp @@ -23,7 +23,7 @@ my_convert(JSContext* context, JS::HandleObject obj, JSType type, JS::MutableHan static JSClass myClass = { "MyClass", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, my_convert }; diff --git a/js/src/jsapi-tests/testProfileStrings.cpp b/js/src/jsapi-tests/testProfileStrings.cpp index bf6a82ca5e85..d02426e19ec6 100644 --- a/js/src/jsapi-tests/testProfileStrings.cpp +++ b/js/src/jsapi-tests/testProfileStrings.cpp @@ -27,7 +27,7 @@ reset(JSContext *cx) } static JSClass ptestClass = { - "Prof", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + "Prof", 0, JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; diff --git a/js/src/jsapi-tests/testPropCache.cpp b/js/src/jsapi-tests/testPropCache.cpp index 3920a1f06bfd..799347bd0567 100644 --- a/js/src/jsapi-tests/testPropCache.cpp +++ b/js/src/jsapi-tests/testPropCache.cpp @@ -20,7 +20,7 @@ CounterAdd(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHand static JSClass CounterClass = { "Counter", /* name */ 0, /* flags */ - CounterAdd, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + CounterAdd, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; diff --git a/js/src/jsapi-tests/testResolveRecursion.cpp b/js/src/jsapi-tests/testResolveRecursion.cpp index 43d7b2d2be99..f5f6bbffa6b5 100644 --- a/js/src/jsapi-tests/testResolveRecursion.cpp +++ b/js/src/jsapi-tests/testResolveRecursion.cpp @@ -20,8 +20,8 @@ BEGIN_TEST(testResolveRecursion) JSCLASS_NEW_RESOLVE | JSCLASS_HAS_PRIVATE, JS_PropertyStub, // add - JS_PropertyStub, // delete - JS_PropertyStub, // get + JS_DeletePropertyStub, // delete + JS_PropertyStub, // get JS_StrictPropertyStub, // set JS_EnumerateStub, (JSResolveOp) my_resolve, diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h index e251ca981a23..60c3ba75d893 100644 --- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -230,7 +230,7 @@ class JSAPITest static JSClass * basicGlobalClass() { static JSClass c = { "global", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; return &c; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3180e7f3e55e..cfba78bcd547 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -880,7 +880,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) data(NULL), gcLock(NULL), gcHelperThread(thisFromCtor()), - sizeOfNonHeapAsmJSArrays_(0), #ifdef JS_THREADSAFE #ifdef JS_ION workerThreadState(NULL), @@ -3197,6 +3196,13 @@ JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool s return JS_TRUE; } +JS_PUBLIC_API(JSBool) +JS_DeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded) +{ + *succeeded = true; + return true; +} + JS_PUBLIC_API(JSBool) JS_EnumerateStub(JSContext *cx, JSHandleObject obj) { @@ -4432,16 +4438,17 @@ JS_DeletePropertyById2(JSContext *cx, JSObject *objArg, jsid id, jsval *rval) RootedValue value(cx); + JSBool succeeded; if (JSID_IS_SPECIAL(id)) { Rooted sid(cx, JSID_TO_SPECIALID(id)); - if (!JSObject::deleteSpecial(cx, obj, sid, &value, false)) + if (!JSObject::deleteSpecial(cx, obj, sid, &succeeded)) return false; } else { - if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &value, false)) + if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &succeeded)) return false; } - *rval = value; + *rval = BooleanValue(succeeded); return true; } @@ -4454,11 +4461,11 @@ JS_DeleteElement2(JSContext *cx, JSObject *objArg, uint32_t index, jsval *rval) assertSameCompartment(cx, obj); JSAutoResolveFlags rf(cx, 0); - RootedValue value(cx); - if (!JSObject::deleteElement(cx, obj, index, &value, false)) + JSBool succeeded; + if (!JSObject::deleteElement(cx, obj, index, &succeeded)) return false; - *rval = value; + *rval = BooleanValue(succeeded); return true; } @@ -4474,11 +4481,11 @@ JS_DeleteProperty2(JSContext *cx, JSObject *objArg, const char *name, jsval *rva if (!atom) return false; - RootedValue value(cx); - if (!JSObject::deleteByValue(cx, obj, StringValue(atom), &value, false)) + JSBool succeeded; + if (!JSObject::deleteByValue(cx, obj, StringValue(atom), &succeeded)) return false; - *rval = value; + *rval = BooleanValue(succeeded); return true; } @@ -4494,11 +4501,11 @@ JS_DeleteUCProperty2(JSContext *cx, JSObject *objArg, const jschar *name, size_t if (!atom) return false; - RootedValue value(cx); - if (!JSObject::deleteByValue(cx, obj, StringValue(atom), &value, false)) + JSBool succeeded; + if (!JSObject::deleteByValue(cx, obj, StringValue(atom), &succeeded)) return false; - *rval = value; + *rval = BooleanValue(succeeded); return true; } @@ -4650,7 +4657,7 @@ static Class prop_iter_class = { "PropertyIterator", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsapi.h b/js/src/jsapi.h index cd4d151ca4f1..846073b1386d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -820,11 +820,9 @@ typedef js::RawValue JSRawValue; /* JSClass operation signatures. */ /* - * Add, delete, or get a property named by id in obj. Note the jsid id - * type -- id may be a string (Unicode property identifier) or an int (element - * index). The *vp out parameter, on success, is the new property value after - * an add or get. After a successful delete, *vp is JSVAL_FALSE iff - * obj[id] can't be deleted (because it's permanent). + * Add or get a property named by id in obj. Note the jsid id type -- id may + * be a string (Unicode property identifier) or an int (element index). The + * *vp out parameter, on success, is the new property value after the action. */ typedef JSBool (* JSPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); @@ -839,6 +837,24 @@ typedef JSBool typedef JSBool (* JSStrictPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); +/* + * Delete a property named by id in obj. + * + * If an error occurred, return false as per normal JSAPI error practice. + * + * If no error occurred, but the deletion attempt wasn't allowed (perhaps + * because the property was non-configurable), set *succeeded to false and + * return true. This will cause |delete obj[id]| to evaluate to false in + * non-strict mode code, and to throw a TypeError in strict mode code. + * + * If no error occurred and the deletion wasn't disallowed (this is *not* the + * same as saying that a deletion actually occurred -- deleting a non-existent + * property, or an inherited property, is allowed -- it's just pointless), + * set *succeeded to true and return true. + */ +typedef JSBool +(* JSDeletePropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); + /* * This function type is used for callbacks that enumerate the properties of * a JSObject. The behavior depends on the value of enum_op: @@ -2810,7 +2826,7 @@ struct JSClass { /* Mandatory non-null function pointer members. */ JSPropertyOp addProperty; - JSPropertyOp delProperty; + JSDeletePropertyOp delProperty; JSPropertyOp getProperty; JSStrictPropertyOp setProperty; JSEnumerateOp enumerate; @@ -2999,6 +3015,9 @@ JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandl extern JS_PUBLIC_API(JSBool) JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); +extern JS_PUBLIC_API(JSBool) +JS_DeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); + extern JS_PUBLIC_API(JSBool) JS_EnumerateStub(JSContext *cx, JSHandleObject obj); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index d3cbcc4be99d..3a54f904630e 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -325,20 +325,19 @@ SetArrayElement(JSContext *cx, HandleObject obj, double index, HandleValue v) } /* - * Delete the element |index| from |obj|. If |strict|, do a strict - * deletion: throw if the property is not configurable. + * Attempt to delete the element |index| from |obj| as if by + * |obj.[[Delete]](index)|. * - * - Return 1 if the deletion succeeds (that is, ES5's [[Delete]] would - * return true) + * If an error occurs while attempting to delete the element (that is, the call + * to [[Delete]] threw), return false. * - * - Return 0 if the deletion fails because the property is not - * configurable (that is, [[Delete]] would return false). Note that if - * |strict| is true we will throw, not return zero. - * - * - Return -1 if an exception occurs (that is, [[Delete]] would throw). + * Otherwise set *succeeded to indicate whether the deletion attempt succeeded + * (that is, whether the call to [[Delete]] returned true or false). (Deletes + * generally fail only when the property is non-configurable, but proxies may + * implement different semantics.) */ -static int -DeleteArrayElement(JSContext *cx, HandleObject obj, double index, bool strict) +static bool +DeleteArrayElement(JSContext *cx, HandleObject obj, double index, JSBool *succeeded) { JS_ASSERT(index >= 0); JS_ASSERT(floor(index) == index); @@ -350,37 +349,34 @@ DeleteArrayElement(JSContext *cx, HandleObject obj, double index, bool strict) obj->markDenseElementsNotPacked(cx); obj->setDenseElement(idx, MagicValue(JS_ELEMENTS_HOLE)); if (!js_SuppressDeletedElement(cx, obj, idx)) - return -1; + return false; } } - return 1; + + *succeeded = true; + return true; } - RootedValue v(cx); - if (index <= UINT32_MAX) { - if (!JSObject::deleteElement(cx, obj, uint32_t(index), &v, strict)) - return -1; - } else { - if (!JSObject::deleteByValue(cx, obj, DoubleValue(index), &v, strict)) - return -1; - } + if (index <= UINT32_MAX) + return JSObject::deleteElement(cx, obj, uint32_t(index), succeeded); - return v.isTrue() ? 1 : 0; + return JSObject::deleteByValue(cx, obj, DoubleValue(index), succeeded); } -/* - * When hole is true, delete the property at the given index. Otherwise set - * its value to v assuming v is rooted. - */ -static JSBool -SetOrDeleteArrayElement(JSContext *cx, HandleObject obj, double index, - JSBool hole, HandleValue v) +/* ES6 20130308 draft 9.3.5 */ +static bool +DeletePropertyOrThrow(JSContext *cx, HandleObject obj, double index) { - if (hole) { - JS_ASSERT(v.isUndefined()); - return DeleteArrayElement(cx, obj, index, true) >= 0; - } - return SetArrayElement(cx, obj, index, v); + JSBool succeeded; + if (!DeleteArrayElement(cx, obj, index, &succeeded)) + return false; + if (succeeded) + return true; + + RootedId id(cx); + if (!ValueToId(cx, NumberValue(index), &id)) + return false; + return obj->reportNotConfigurable(cx, id, JSREPORT_ERROR); } JSBool @@ -475,10 +471,20 @@ array_length_setter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, JSObject::setArrayLength(cx, obj, oldlen + 1); return false; } - int deletion = DeleteArrayElement(cx, obj, oldlen, strict); - if (deletion <= 0) { + + JSBool succeeded; + if (!DeleteArrayElement(cx, obj, oldlen, &succeeded)) + return false; + if (!succeeded) { JSObject::setArrayLength(cx, obj, oldlen + 1); - return deletion >= 0; + if (!strict) + return true; + + RootedId id(cx); + if (!IndexToId(cx, oldlen, &id)) + return false; + obj->reportNotConfigurable(cx, id); + return false; } } while (oldlen != newlen); } else { @@ -500,10 +506,18 @@ array_length_setter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, return false; if (JSID_IS_VOID(nid)) break; + + // XXX Bug! We should fail fast on the highest non-configurable + // property we find, as we do in the simple-loop case above. + // But since we're iterating in unknown order here, we don't + // know if we're hitting the highest non-configurable property + // when we hit a failure. For now just drop unsuccessful + // deletion on the floor, as the previous code here did. uint32_t index; - RootedValue junk(cx); + JSBool succeeded; if (js_IdIsIndex(nid, &index) && index - newlen < gap && - !JSObject::deleteElement(cx, obj, index, &junk, false)) { + !JSObject::deleteElement(cx, obj, index, &succeeded)) + { return false; } } @@ -567,7 +581,7 @@ Class js::ArrayClass = { "Array", JSCLASS_HAS_CACHED_PROTO(JSProto_Array), array_addProperty, - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1044,11 +1058,29 @@ array_reverse(JSContext *cx, unsigned argc, Value *vp) JSBool hole, hole2; if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, obj, i, &hole, &lowval) || - !GetElement(cx, obj, len - i - 1, &hole2, &hival) || - !SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, lowval) || - !SetOrDeleteArrayElement(cx, obj, i, hole2, hival)) { + !GetElement(cx, obj, len - i - 1, &hole2, &hival)) + { return false; } + + if (!hole && !hole2) { + if (!SetArrayElement(cx, obj, i, hival)) + return false; + if (!SetArrayElement(cx, obj, len - i - 1, lowval)) + return false; + } else if (hole && !hole2) { + if (!SetArrayElement(cx, obj, i, hival)) + return false; + if (!DeletePropertyOrThrow(cx, obj, len - i - 1)) + return false; + } else if (!hole && hole2) { + if (!DeletePropertyOrThrow(cx, obj, i)) + return false; + if (!SetArrayElement(cx, obj, len - i - 1, lowval)) + return false; + } else { + // No action required. + } } args.rval().setObject(*obj); return true; @@ -1657,7 +1689,7 @@ js::array_sort(JSContext *cx, unsigned argc, Value *vp) /* Re-create any holes that sorted to the end of the array. */ while (len > n) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0) + if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeletePropertyOrThrow(cx, obj, --len)) return false; } args.rval().setObject(*obj); @@ -1760,7 +1792,7 @@ array_pop_slowly(JSContext *cx, HandleObject obj, CallArgs &args) if (!GetElement(cx, obj, index, &hole, &elt)) return false; - if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + if (!hole && !DeletePropertyOrThrow(cx, obj, index)) return false; args.rval().set(elt); @@ -1783,7 +1815,7 @@ array_pop_dense(JSContext *cx, HandleObject obj, CallArgs &args) if (!GetElement(cx, obj, index, &hole, &elt)) return false; - if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) + if (!hole && !DeletePropertyOrThrow(cx, obj, index)) return false; args.rval().set(elt); @@ -1871,15 +1903,21 @@ js::array_shift(JSContext *cx, unsigned argc, Value *vp) /* Slide down the array above the first element. */ RootedValue value(cx); for (uint32_t i = 0; i < length; i++) { - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, i + 1, &hole, &value) || - !SetOrDeleteArrayElement(cx, obj, i, hole, value)) { - return JS_FALSE; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + if (!GetElement(cx, obj, i + 1, &hole, &value)) + return false; + if (hole) { + if (!DeletePropertyOrThrow(cx, obj, i)) + return false; + } else { + if (!SetArrayElement(cx, obj, i, value)) + return false; } } /* Delete the only or last element when it exists. */ - if (!hole && DeleteArrayElement(cx, obj, length, true) < 0) + if (!hole && !DeletePropertyOrThrow(cx, obj, length)) return JS_FALSE; } return SetLengthProperty(cx, obj, length); @@ -1927,10 +1965,16 @@ array_unshift(JSContext *cx, unsigned argc, Value *vp) do { --last, --upperIndex; JSBool hole; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, last, &hole, &value) || - !SetOrDeleteArrayElement(cx, obj, upperIndex, hole, value)) { - return JS_FALSE; + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + if (!GetElement(cx, obj, last, &hole, &value)) + return false; + if (hole) { + if (!DeletePropertyOrThrow(cx, obj, upperIndex)) + return false; + } else { + if (!SetArrayElement(cx, obj, upperIndex, value)) + return false; } } while (last != 0); } @@ -2115,18 +2159,24 @@ array_splice(JSContext *cx, unsigned argc, Value *vp) /* Steps 12(a)-(b). */ RootedValue fromValue(cx); for (uint32_t from = sourceIndex, to = targetIndex; from < len; from++, to++) { - JSBool hole; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, from, &hole, &fromValue) || - !SetOrDeleteArrayElement(cx, obj, to, hole, fromValue)) - { + if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; + + JSBool hole; + if (!GetElement(cx, obj, from, &hole, &fromValue)) + return false; + if (hole) { + if (!DeletePropertyOrThrow(cx, obj, to)) + return false; + } else { + if (!SetArrayElement(cx, obj, to, fromValue)) + return false; } } /* Steps 12(c)-(d). */ for (uint32_t k = len; k > finalLength; k--) { - if (DeleteArrayElement(cx, obj, k - 1, true) < 0) + if (!DeletePropertyOrThrow(cx, obj, k - 1)) return false; } } @@ -2155,15 +2205,22 @@ array_splice(JSContext *cx, unsigned argc, Value *vp) } else { RootedValue fromValue(cx); for (double k = len - actualDeleteCount; k > actualStart; k--) { + if (!JS_CHECK_OPERATION_LIMIT(cx)) + return false; + double from = k + actualDeleteCount - 1; double to = k + itemCount - 1; JSBool hole; - if (!JS_CHECK_OPERATION_LIMIT(cx) || - !GetElement(cx, obj, from, &hole, &fromValue) || - !SetOrDeleteArrayElement(cx, obj, to, hole, fromValue)) - { + if (!GetElement(cx, obj, from, &hole, &fromValue)) return false; + + if (hole) { + if (!DeletePropertyOrThrow(cx, obj, to)) + return false; + } else { + if (!SetArrayElement(cx, obj, to, fromValue)) + return false; } } } diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index b3a54c63c24e..843c3294c8b8 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -38,8 +38,9 @@ using namespace js::types; Class js::BooleanClass = { "Boolean", - JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), + JS_PropertyStub, /* addProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsclass.h b/js/src/jsclass.h index 86c0e5b86e68..bb01ff046043 100644 --- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -180,11 +180,11 @@ typedef JSBool typedef JSBool (* SpecialAttributesOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp); typedef JSBool -(* DeletePropertyOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp, JSBool strict); +(* DeletePropertyOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, JSBool *succeeded); typedef JSBool -(* DeleteElementOp)(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp, JSBool strict); +(* DeleteElementOp)(JSContext *cx, HandleObject obj, uint32_t index, JSBool *succeeded); typedef JSBool -(* DeleteSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleValue vp, JSBool strict); +(* DeleteSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSBool *succeeded); typedef JSObject * @@ -198,7 +198,7 @@ typedef void \ /* Mandatory non-null function pointer members. */ \ JSPropertyOp addProperty; \ - JSPropertyOp delProperty; \ + JSDeletePropertyOp delProperty; \ JSPropertyOp getProperty; \ JSStrictPropertyOp setProperty; \ JSEnumerateOp enumerate; \ diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 2190cf5be7ae..9da194a90cf8 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -143,24 +143,6 @@ JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, JS::RuntimeSizes rtSizes->scriptData += mallocSizeOf(r.front()); } -size_t -JSRuntime::sizeOfExplicitNonHeap() -{ - size_t n = stackSpace.sizeOf(); - - if (execAlloc_) { - JS::CodeSizes sizes; - execAlloc_->sizeOfCode(&sizes); - n += sizes.jaeger + sizes.ion + sizes.baseline + sizes.asmJS + - sizes.regexp + sizes.other + sizes.unused; - } - - if (bumpAlloc_) - n += bumpAlloc_->sizeOfNonHeapData(); - - return n; -} - void JSRuntime::triggerOperationCallback() { diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index fd90371f11b8..01ca74eba0e7 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1204,8 +1204,6 @@ struct JSRuntime : private JS::shadow::Runtime, js::AsmJSMachExceptionHandler asmJSMachExceptionHandler; #endif - size_t sizeOfNonHeapAsmJSArrays_; - #ifdef JS_THREADSAFE # ifdef JS_ION js::WorkerThreadState *workerThreadState; @@ -1405,7 +1403,6 @@ struct JSRuntime : private JS::shadow::Runtime, } void sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, JS::RuntimeSizes *runtime); - size_t sizeOfExplicitNonHeap(); private: diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 9c9a03d3b1da..604b206b5ab9 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -422,6 +422,16 @@ CallJSPropertyOpSetter(JSContext *cx, StrictPropertyOp op, HandleObject obj, Han return op(cx, obj, id, strict, vp); } +static inline bool +CallJSDeletePropertyOp(JSContext *cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id, + JSBool *succeeded) +{ + JS_CHECK_RECURSION(cx, return false); + + assertSameCompartment(cx, receiver, id); + return op(cx, receiver, id, succeeded); +} + inline bool CallSetter(JSContext *cx, HandleObject obj, HandleId id, StrictPropertyOp op, unsigned attrs, unsigned shortid, JSBool strict, MutableHandleValue vp) diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 928c4a66a8ea..b3ce396f860d 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -511,7 +511,7 @@ Class js::DateClass = { JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Date), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 21d2a3afeb9e..68a5e1da59c2 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -68,7 +68,7 @@ Class js::ErrorClass = { JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Error), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 96d9eb2a4057..80ab7636f8a9 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -548,7 +548,7 @@ JS_FRIEND_DATA(Class) js::FunctionClass = { JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_Function), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ fun_enumerate, diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 68b4c69e57b2..f1bb3881c222 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -177,7 +177,7 @@ const uint32_t JSSLOT_SAVED_ID = 1; Class js_NoSuchMethodClass = { "NoSuchMethod", JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, }; @@ -2129,9 +2129,15 @@ BEGIN_CASE(JSOP_DELPROP) RootedObject &obj = rootObject0; FETCH_OBJECT(cx, -1, obj); - MutableHandleValue res = MutableHandleValue::fromMarkedLocation(®s.sp[-1]); - if (!JSObject::deleteProperty(cx, obj, name, res, script->strict)) + JSBool succeeded; + if (!JSObject::deleteProperty(cx, obj, name, &succeeded)) goto error; + if (!succeeded && script->strict) { + obj->reportNotConfigurable(cx, NameToId(name)); + goto error; + } + MutableHandleValue res = MutableHandleValue::fromMarkedLocation(®s.sp[-1]); + res.setBoolean(succeeded); } END_CASE(JSOP_DELPROP) @@ -2144,10 +2150,22 @@ BEGIN_CASE(JSOP_DELELEM) RootedValue &propval = rootValue0; propval = regs.sp[-1]; - MutableHandleValue res = MutableHandleValue::fromMarkedLocation(®s.sp[-2]); - if (!JSObject::deleteByValue(cx, obj, propval, res, script->strict)) + JSBool succeeded; + if (!JSObject::deleteByValue(cx, obj, propval, &succeeded)) goto error; + if (!succeeded && script->strict) { + // XXX This observably calls ToString(propval). We should convert to + // PropertyKey and use that to delete, and to report an error if + // necessary! + RootedId id(cx); + if (!ValueToId(cx, propval, &id)) + goto error; + obj->reportNotConfigurable(cx, id); + goto error; + } + MutableHandleValue res = MutableHandleValue::fromMarkedLocation(®s.sp[-2]); + res.setBoolean(succeeded); regs.sp--; } END_CASE(JSOP_DELELEM) @@ -3613,22 +3631,17 @@ template bool js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, JSBool *bp) { - // default op result is false (failure) - *bp = true; - // convert value to JSObject pointer RootedObject obj(cx, ToObjectFromStack(cx, v)); if (!obj) return false; - // Call deleteProperty on obj - RootedValue result(cx, NullValue()); - bool delprop_ok = JSObject::deleteProperty(cx, obj, name, &result, strict); - if (!delprop_ok) + if (!JSObject::deleteProperty(cx, obj, name, bp)) return false; - - // convert result into *bp and return - *bp = result.toBoolean(); + if (strict && !*bp) { + obj->reportNotConfigurable(cx, NameToId(name)); + return false; + } return true; } @@ -3643,16 +3656,23 @@ js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, JSBool *bp) if (!obj) return false; - RootedValue result(cx); - if (!JSObject::deleteByValue(cx, obj, index, &result, strict)) + if (!JSObject::deleteByValue(cx, obj, index, bp)) return false; - - *bp = result.toBoolean(); + if (strict && !*bp) { + // XXX This observably calls ToString(propval). We should convert to + // PropertyKey and use that to delete, and to report an error if + // necessary! + RootedId id(cx); + if (!ValueToId(cx, index, &id)) + return false; + obj->reportNotConfigurable(cx, id); + return false; + } return true; } -template bool js::DeleteElement (JSContext *, HandleValue, HandleValue, JSBool *); -template bool js::DeleteElement(JSContext *, HandleValue, HandleValue, JSBool *); +template bool js::DeleteElement (JSContext *, HandleValue, HandleValue, JSBool *succeeded); +template bool js::DeleteElement(JSContext *, HandleValue, HandleValue, JSBool *succeeded); bool js::GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue vp) @@ -3755,10 +3775,16 @@ js::DeleteNameOperation(JSContext *cx, HandlePropertyName name, HandleObject sco if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape)) return false; - /* ECMA says to return true if name is undefined or inherited. */ - res.setBoolean(true); - if (shape) - return JSObject::deleteProperty(cx, scope, name, res, false); + if (!scope) { + // Return true for non-existent names. + res.setBoolean(true); + return true; + } + + JSBool succeeded; + if (!JSObject::deleteProperty(cx, scope, name, &succeeded)) + return false; + res.setBoolean(succeeded); return true; } diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 552bdd95fb13..0308f4daee56 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -837,7 +837,7 @@ Class PropertyIteratorObject::class_ = { JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -940,7 +940,7 @@ Class js::ElementIteratorClass = { JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(ElementIteratorObject::NumSlots), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1298,7 +1298,7 @@ Class js::StopIterationClass = { JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration) | JSCLASS_FREEZE_PROTO, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -1395,7 +1395,7 @@ Class js::GeneratorClass = { "Generator", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 97f880fe98d0..aa0526391cac 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -86,7 +86,7 @@ Class js::MathClass = { js_Math_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Math), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsmemorymetrics.cpp b/js/src/jsmemorymetrics.cpp index fc82601c5c17..351d965446e5 100644 --- a/js/src/jsmemorymetrics.cpp +++ b/js/src/jsmemorymetrics.cpp @@ -375,29 +375,6 @@ JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisit return true; } -JS_PUBLIC_API(int64_t) -JS::GetExplicitNonHeapForRuntime(JSRuntime *rt, JSMallocSizeOfFun mallocSizeOf) -{ - // explicit/*/gc-heap/* - size_t n = size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize; - - // Subtract decommitted arenas, which aren't included in "explicit". - size_t decommittedArenas = 0; - IterateChunks(rt, &decommittedArenas, DecommittedArenasChunkCallback); - n -= decommittedArenas; - - // explicit/*/objects-extra/elements/asm.js (64-bit platforms only) - n += rt->sizeOfNonHeapAsmJSArrays_; - - // explicit/runtime/mjit-code - // explicit/runtime/regexp-code - // explicit/runtime/stack-committed - // explicit/runtime/unused-code-memory - n += rt->sizeOfExplicitNonHeap(); - - return int64_t(n); -} - JS_PUBLIC_API(size_t) JS::SystemCompartmentCount(JSRuntime *rt) { diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 8c9dc7aff420..e89b967840ae 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -409,7 +409,7 @@ Class js::NumberClass = { js_Number_str, JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f8cb8b97e8a4..50097ee541bc 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -82,7 +82,7 @@ Class js::ObjectClass = { js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Object), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -908,8 +908,8 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD * redefining it or we had invoked its setter to change its value). */ if (callDelProperty) { - RootedValue dummy(cx, UndefinedValue()); - if (!CallJSPropertyOp(cx, obj2->getClass()->delProperty, obj2, id, &dummy)) + JSBool succeeded; + if (!CallJSDeletePropertyOp(cx, obj2->getClass()->delProperty, obj2, id, &succeeded)) return false; } @@ -1617,27 +1617,26 @@ JSObject::nonNativeSetElement(JSContext *cx, HandleObject obj, } /* static */ bool -JSObject::deleteByValue(JSContext *cx, HandleObject obj, - const Value &property, MutableHandleValue rval, bool strict) +JSObject::deleteByValue(JSContext *cx, HandleObject obj, const Value &property, JSBool *succeeded) { uint32_t index; if (IsDefinitelyIndex(property, &index)) - return deleteElement(cx, obj, index, rval, strict); + return deleteElement(cx, obj, index, succeeded); RootedValue propval(cx, property); Rooted sid(cx); if (ValueIsSpecial(obj, &propval, &sid, cx)) - return deleteSpecial(cx, obj, sid, rval, strict); + return deleteSpecial(cx, obj, sid, succeeded); JSAtom *name = ToAtom(cx, propval); if (!name) return false; if (name->isIndex(&index)) - return deleteElement(cx, obj, index, rval, strict); + return deleteElement(cx, obj, index, succeeded); Rooted propname(cx, name->asPropertyName()); - return deleteProperty(cx, obj, propname, rval, strict); + return deleteProperty(cx, obj, propname, succeeded); } JS_FRIEND_API(bool) @@ -2225,8 +2224,8 @@ js::DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey ke bad: if (named) { - RootedValue rval(cx); - JSObject::deleteByValue(cx, obj, StringValue(atom), &rval, false); + JSBool succeeded; + JSObject::deleteByValue(cx, obj, StringValue(atom), &succeeded); } if (cached) ClearClassObject(obj, key); @@ -4367,10 +4366,8 @@ baseops::SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, u } JSBool -baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue rval, JSBool strict) +baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded) { - rval.setBoolean(true); - RootedObject proto(cx); RootedShape shape(cx); if (!baseops::LookupProperty(cx, obj, id, &proto, &shape)) @@ -4378,17 +4375,17 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHand if (!shape || proto != obj) { /* * If no property, or the property comes from a prototype, call the - * class's delProperty hook, passing rval as the result parameter. + * class's delProperty hook, passing succeeded as the result parameter. */ - return CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval); + return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded); } GCPoke(cx->runtime); if (IsImplicitDenseElement(shape)) { - if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval)) + if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, succeeded)) return false; - if (rval.isFalse()) + if (!succeeded) return true; JSObject::setDenseElementHole(cx, obj, JSID_TO_INT(id)); @@ -4396,9 +4393,7 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHand } if (!shape->configurable()) { - if (strict) - return obj->reportNotConfigurable(cx, id); - rval.setBoolean(false); + *succeeded = false; return true; } @@ -4406,9 +4401,9 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHand if (!shape->getUserId(cx, &userid)) return false; - if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, userid, rval)) + if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, userid, succeeded)) return false; - if (rval.isFalse()) + if (!succeeded) return true; return obj->removeProperty(cx, id) && js_SuppressDeletedProperty(cx, obj, id); @@ -4416,28 +4411,26 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHand JSBool baseops::DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, - MutableHandleValue rval, JSBool strict) + JSBool *succeeded) { Rooted id(cx, NameToId(name)); - return baseops::DeleteGeneric(cx, obj, id, rval, strict); + return baseops::DeleteGeneric(cx, obj, id, succeeded); } JSBool -baseops::DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, - MutableHandleValue rval, JSBool strict) +baseops::DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, JSBool *succeeded) { RootedId id(cx); if (!IndexToId(cx, index, &id)) return false; - return baseops::DeleteGeneric(cx, obj, id, rval, strict); + return baseops::DeleteGeneric(cx, obj, id, succeeded); } JSBool -baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, - MutableHandleValue rval, JSBool strict) +baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSBool *succeeded) { Rooted id(cx, SPECIALID_TO_JSID(sid)); - return baseops::DeleteGeneric(cx, obj, id, rval, strict); + return baseops::DeleteGeneric(cx, obj, id, succeeded); } bool diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 25a8652c5ec5..919e33229145 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -192,16 +192,16 @@ extern JSBool SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp); extern JSBool -DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue rval, JSBool strict); +DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSBool *succeeded); extern JSBool -DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue rval, JSBool strict); +DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, JSBool *succeeded); extern JSBool -DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleValue rval, JSBool strict); +DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSBool *succeeded); extern JSBool -DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue rval, JSBool strict); +DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded); } /* namespace js::baseops */ @@ -892,15 +892,13 @@ class JSObject : public js::ObjectImpl static inline bool deleteProperty(JSContext *cx, js::HandleObject obj, js::HandlePropertyName name, - js::MutableHandleValue rval, bool strict); + JSBool *succeeded); static inline bool deleteElement(JSContext *cx, js::HandleObject obj, - uint32_t index, - js::MutableHandleValue rval, bool strict); + uint32_t index, JSBool *succeeded); static inline bool deleteSpecial(JSContext *cx, js::HandleObject obj, - js::HandleSpecialId sid, - js::MutableHandleValue rval, bool strict); + js::HandleSpecialId sid, JSBool *succeeded); static bool deleteByValue(JSContext *cx, js::HandleObject obj, - const js::Value &property, js::MutableHandleValue rval, bool strict); + const js::Value &property, JSBool *succeeded); static inline bool enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, JS::MutableHandleValue statep, JS::MutableHandleId idp); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 9213ae088914..a78e32222ba7 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -194,19 +194,18 @@ JSObject::getPropertyNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, } /* static */ inline bool -JSObject::deleteProperty(JSContext *cx, js::HandleObject obj, - js::HandlePropertyName name, js::MutableHandleValue rval, bool strict) +JSObject::deleteProperty(JSContext *cx, js::HandleObject obj, js::HandlePropertyName name, + JSBool *succeeded) { JS::RootedId id(cx, js::NameToId(name)); js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType()); js::types::MarkTypePropertyConfigured(cx, obj, id); js::DeletePropertyOp op = obj->getOps()->deleteProperty; - return (op ? op : js::baseops::DeleteProperty)(cx, obj, name, rval, strict); + return (op ? op : js::baseops::DeleteProperty)(cx, obj, name, succeeded); } /* static */ inline bool -JSObject::deleteElement(JSContext *cx, js::HandleObject obj, - uint32_t index, js::MutableHandleValue rval, bool strict) +JSObject::deleteElement(JSContext *cx, js::HandleObject obj, uint32_t index, JSBool *succeeded) { JS::RootedId id(cx); if (!js::IndexToId(cx, index, &id)) @@ -214,18 +213,18 @@ JSObject::deleteElement(JSContext *cx, js::HandleObject obj, js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType()); js::types::MarkTypePropertyConfigured(cx, obj, id); js::DeleteElementOp op = obj->getOps()->deleteElement; - return (op ? op : js::baseops::DeleteElement)(cx, obj, index, rval, strict); + return (op ? op : js::baseops::DeleteElement)(cx, obj, index, succeeded); } /* static */ inline bool -JSObject::deleteSpecial(JSContext *cx, js::HandleObject obj, - js::HandleSpecialId sid, js::MutableHandleValue rval, bool strict) +JSObject::deleteSpecial(JSContext *cx, js::HandleObject obj, js::HandleSpecialId sid, + JSBool *succeeded) { JS::RootedId id(cx, SPECIALID_TO_JSID(sid)); js::types::AddTypePropertyId(cx, obj, id, js::types::Type::UndefinedType()); js::types::MarkTypePropertyConfigured(cx, obj, id); js::DeleteSpecialOp op = obj->getOps()->deleteSpecial; - return (op ? op : js::baseops::DeleteSpecial)(cx, obj, sid, rval, strict); + return (op ? op : js::baseops::DeleteSpecial)(cx, obj, sid, succeeded); } inline void diff --git a/js/src/json.cpp b/js/src/json.cpp index d03a8da9931f..66e73b9dea9a 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -45,7 +45,7 @@ Class js::JSONClass = { js_JSON_str, JSCLASS_HAS_CACHED_PROTO(JSProto_JSON), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -776,7 +776,8 @@ Walk(JSContext *cx, HandleObject holder, HandleId name, HandleValue reviver, Mut if (newElement.isUndefined()) { /* Step 2a(iii)(2). */ - if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &newElement, false)) + JSBool succeeded; + if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &succeeded)) return false; } else { /* Step 2a(iii)(3). */ @@ -804,7 +805,8 @@ Walk(JSContext *cx, HandleObject holder, HandleId name, HandleValue reviver, Mut if (newElement.isUndefined()) { /* Step 2b(ii)(2). */ - if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &newElement, false)) + JSBool succeeded; + if (!JSObject::deleteByValue(cx, obj, IdToValue(id), &succeeded)) return false; } else { /* Step 2b(ii)(3). */ diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index dda39fda162d..23220564a573 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -2948,41 +2948,36 @@ proxy_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, } static JSBool -proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, - MutableHandleValue rval, JSBool strict) +proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded) { - // TODO: throwing away strict bool deleted; - if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id)) + if (!Proxy::delete_(cx, obj, id, &deleted)) return false; - rval.setBoolean(deleted); - return true; + *succeeded = deleted; + return js_SuppressDeletedProperty(cx, obj, id); } static JSBool -proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, - MutableHandleValue rval, JSBool strict) +proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSBool *succeeded) { Rooted id(cx, NameToId(name)); - return proxy_DeleteGeneric(cx, obj, id, rval, strict); + return proxy_DeleteGeneric(cx, obj, id, succeeded); } static JSBool -proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, - MutableHandleValue rval, JSBool strict) +proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, JSBool *succeeded) { RootedId id(cx); if (!IndexToId(cx, index, &id)) return false; - return proxy_DeleteGeneric(cx, obj, id, rval, strict); + return proxy_DeleteGeneric(cx, obj, id, succeeded); } static JSBool -proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, - MutableHandleValue rval, JSBool strict) +proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSBool *succeeded) { Rooted id(cx, SPECIALID_TO_JSID(sid)); - return proxy_DeleteGeneric(cx, obj, id, rval, strict); + return proxy_DeleteGeneric(cx, obj, id, succeeded); } static void @@ -3070,7 +3065,7 @@ JS_FRIEND_DATA(Class) js::ObjectProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -3121,7 +3116,7 @@ JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -3196,7 +3191,7 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(6), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -3368,7 +3363,7 @@ Class js::ProxyClass = { "Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index c978f3d2c967..ed61d59d663b 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1688,7 +1688,6 @@ JSScript::Create(JSContext *cx, HandleObject enclosingScope, bool savedCallerFun script->sourceStart = bufStart; script->sourceEnd = bufEnd; script->userBit = options.userBit; - script->maxInlineDepth_ = uint8_t(-1); return script; } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 34cd5055602b..595287a6b12b 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -427,6 +427,9 @@ class JSScript : public js::gc::Cell // 16-bit fields. + private: + uint16_t PADDING16; + uint16_t version; /* JS version under which script was compiled */ public: @@ -442,11 +445,6 @@ class JSScript : public js::gc::Cell uint16_t staticLevel;/* static level for display maintenance */ // 8-bit fields. - private: - uint8_t maxInlineDepth_; /* script max inline depth (IonMonkey) - uint8_t(-1): unitialized - uint8_t(-2): disabled */ - uint8_t PADDING8; public: // The kinds of the optional arrays. @@ -810,26 +808,6 @@ class JSScript : public js::gc::Cell return maxLoopCount; } - void setMaxInlineDepth(uint32_t maxInlineDepth) { - if (maxInlineDepth >= uint8_t(-2)) { - disableInlineDepthCheck(); - return; - } - maxInlineDepth_ = maxInlineDepth; - } - - uint8_t maxInlineDepth() const { - return maxInlineDepth_; - } - - void disableInlineDepthCheck() { - maxInlineDepth_ = uint8_t(-2); - } - - bool isInlineDepthCheckDisabled() { - return maxInlineDepth_ == uint8_t(-2); - } - /* * Size of the JITScript and all sections. If |mallocSizeOf| is NULL, the * size is computed analytically. (This method is implemented in diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 0e50cb0f7f74..de0dd134c7aa 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -424,7 +424,7 @@ Class js::StringClass = { JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ str_enumerate, diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 15b5c5daf67b..bc07ee898708 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -379,11 +379,6 @@ ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle buf } # endif - // We don't include the PageSize at the front so that when we sum the - // individual asm.js arrays for all the compartments in the runtime, they - // match this number. - buffer->runtime()->sizeOfNonHeapAsmJSArrays_ += buffer->byteLength(); - // Copy over the current contents of the typed array. uint8_t *data = reinterpret_cast(p) + PageSize; memcpy(data, buffer->dataPointer(), buffer->byteLength()); @@ -407,8 +402,6 @@ ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, RawObject obj) ArrayBufferObject &buffer = obj->asArrayBuffer(); JS_ASSERT(buffer.isAsmJSArrayBuffer()); - buffer.runtime()->sizeOfNonHeapAsmJSArrays_ -= buffer.byteLength(); - uint8_t *p = buffer.dataPointer() - PageSize ; JS_ASSERT(uintptr_t(p) % PageSize == 0); # ifdef XP_WIN @@ -1087,33 +1080,33 @@ ArrayBufferObject::obj_setSpecialAttributes(JSContext *cx, HandleObject obj, } JSBool -ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, - HandlePropertyName name, MutableHandleValue rval, JSBool strict) +ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, + JSBool *succeeded) { RootedObject delegate(cx, ArrayBufferDelegate(cx, obj)); if (!delegate) return false; - return baseops::DeleteProperty(cx, delegate, name, rval, strict); + return baseops::DeleteProperty(cx, delegate, name, succeeded); } JSBool -ArrayBufferObject::obj_deleteElement(JSContext *cx, HandleObject obj, - uint32_t index, MutableHandleValue rval, JSBool strict) +ArrayBufferObject::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, + JSBool *succeeded) { RootedObject delegate(cx, ArrayBufferDelegate(cx, obj)); if (!delegate) return false; - return baseops::DeleteElement(cx, delegate, index, rval, strict); + return baseops::DeleteElement(cx, delegate, index, succeeded); } JSBool -ArrayBufferObject::obj_deleteSpecial(JSContext *cx, HandleObject obj, - HandleSpecialId sid, MutableHandleValue rval, JSBool strict) +ArrayBufferObject::obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, + JSBool *succeeded) { RootedObject delegate(cx, ArrayBufferDelegate(cx, obj)); if (!delegate) return false; - return baseops::DeleteSpecial(cx, delegate, sid, rval, strict); + return baseops::DeleteSpecial(cx, delegate, sid, succeeded); } JSBool @@ -1628,33 +1621,30 @@ class TypedArrayTemplate } static JSBool - obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, - MutableHandleValue rval, JSBool strict) + obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSBool *succeeded) { - rval.setBoolean(true); + *succeeded = true; return true; } static JSBool - obj_deleteElement(JSContext *cx, HandleObject tarray, uint32_t index, - MutableHandleValue rval, JSBool strict) + obj_deleteElement(JSContext *cx, HandleObject tarray, uint32_t index, JSBool *succeeded) { JS_ASSERT(tarray->isTypedArray()); if (index < length(tarray)) { - rval.setBoolean(false); + *succeeded = false; return true; } - rval.setBoolean(true); + *succeeded = true; return true; } static JSBool - obj_deleteSpecial(JSContext *cx, HandleObject tarray, HandleSpecialId sid, - MutableHandleValue rval, JSBool strict) + obj_deleteSpecial(JSContext *cx, HandleObject tarray, HandleSpecialId sid, JSBool *succeeded) { - rval.setBoolean(true); + *succeeded = true; return true; } @@ -3279,7 +3269,7 @@ Class ArrayBufferObject::protoClass = { JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -3295,7 +3285,7 @@ Class js::ArrayBufferClass = { JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -3443,7 +3433,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) JSCLASS_HAS_PRIVATE | \ JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \ JS_PropertyStub, /* addProperty */ \ - JS_PropertyStub, /* delProperty */ \ + JS_DeletePropertyStub, /* delProperty */ \ JS_PropertyStub, /* getProperty */ \ JS_StrictPropertyStub, /* setProperty */ \ JS_EnumerateStub, \ @@ -3459,7 +3449,7 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double) JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray) | \ Class::NON_NATIVE, \ JS_PropertyStub, /* addProperty */ \ - JS_PropertyStub, /* delProperty */ \ + JS_DeletePropertyStub, /* delProperty */ \ JS_PropertyStub, /* getProperty */ \ JS_StrictPropertyStub, /* setProperty */ \ JS_EnumerateStub, \ @@ -3659,7 +3649,7 @@ Class js::DataViewObject::protoClass = { JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -3674,7 +3664,7 @@ Class js::DataViewClass = { JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h index e38313b16299..08ad9479e92c 100644 --- a/js/src/jstypedarray.h +++ b/js/src/jstypedarray.h @@ -119,15 +119,12 @@ class ArrayBufferObject : public JSObject static JSBool obj_setSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp); - static JSBool obj_deleteProperty(JSContext *cx, HandleObject obj, - HandlePropertyName name, MutableHandleValue rval, - JSBool strict); - static JSBool obj_deleteElement(JSContext *cx, HandleObject obj, - uint32_t index, MutableHandleValue rval, - JSBool strict); - static JSBool obj_deleteSpecial(JSContext *cx, HandleObject obj, - HandleSpecialId sid, MutableHandleValue rval, - JSBool strict); + static JSBool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, + JSBool *succeeded); + static JSBool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, + JSBool *succeeded); + static JSBool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, + JSBool *succeeded); static JSBool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, MutableHandleValue statep, MutableHandleId idp); diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 5977bfca5971..dc0abbea626b 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -399,7 +399,7 @@ Class js::WeakMapClass = { JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index c9fda4f151fe..5a6a8f956c2b 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -1357,8 +1357,11 @@ stubs::DelName(VMFrame &f, PropertyName *name_) f.regs.sp++; f.regs.sp[-1] = BooleanValue(true); if (prop) { - if (!JSObject::deleteProperty(f.cx, obj, name, MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]), false)) + JSBool succeeded; + if (!JSObject::deleteProperty(f.cx, obj, name, &succeeded)) THROW(); + MutableHandleValue rval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]); + rval.setBoolean(succeeded); } } @@ -1374,11 +1377,15 @@ stubs::DelProp(VMFrame &f, PropertyName *name_) if (!obj) THROW(); - RootedValue rval(cx); - if (!JSObject::deleteProperty(cx, obj, name, &rval, strict)) + JSBool succeeded; + if (!JSObject::deleteProperty(cx, obj, name, &succeeded)) THROW(); + if (strict && !succeeded) { + obj->reportNotConfigurable(cx, NameToId(name)); + THROW(); + } - f.regs.sp[-1] = rval; + f.regs.sp[-1] = BooleanValue(succeeded); } template void JS_FASTCALL stubs::DelProp(VMFrame &f, PropertyName *name); @@ -1396,10 +1403,22 @@ stubs::DelElem(VMFrame &f) THROW(); const Value &propval = f.regs.sp[-1]; - MutableHandleValue rval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]); - - if (!JSObject::deleteByValue(cx, obj, propval, rval, strict)) + JSBool succeeded; + if (!JSObject::deleteByValue(cx, obj, propval, &succeeded)) THROW(); + if (strict && !succeeded) { + // XXX This observably calls ToString(propval). We should convert to + // PropertyKey and use that to delete, and to report an error if + // necessary -- but this code's all dying soon, so who cares? + RootedId id(cx); + if (!ValueToId(cx, propval, &id)) + THROW(); + obj->reportNotConfigurable(cx, id); + THROW(); + } + + MutableHandleValue rval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]); + rval.setBoolean(succeeded); } void JS_FASTCALL diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp index 098361a964a4..7caa12a50a28 100644 --- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -156,7 +156,7 @@ static void pm_finalize(JSFreeOp* fop, JSObject* obj); static JSClass pm_class = { "PerfMeasurement", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize }; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 68f0c08168de..4c496dc4f09b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2450,7 +2450,7 @@ sandbox_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, static JSClass sandbox_class = { "sandbox", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, sandbox_enumerate, (JSResolveOp)sandbox_resolve, JS_ConvertStub @@ -2713,7 +2713,7 @@ resolver_enumerate(JSContext *cx, HandleObject obj) static JSClass resolver_class = { "resolver", JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1), - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, resolver_enumerate, (JSResolveOp)resolver_resolve, JS_ConvertStub @@ -3526,7 +3526,7 @@ ObjectEmulatingUndefined(JSContext *cx, unsigned argc, jsval *vp) "ObjectEmulatingUndefined", JSCLASS_EMULATES_UNDEFINED, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, @@ -4040,15 +4040,20 @@ its_addProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue } static JSBool -its_delProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) +its_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded) { - if (!its_noisy) + if (!its_noisy) { + *succeeded = true; return true; + } ToStringHelper idString(cx, id); + if (idString.threw()) + return false; + fprintf(gOutFile, "deleting its property %s,", idString.getBytes()); - ToStringHelper valueString(cx, vp); - fprintf(gOutFile, " initial value %s\n", valueString.getBytes()); + + *succeeded = true; return true; } @@ -4397,7 +4402,7 @@ global_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, JSClass global_class = { "global", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, global_enumerate, (JSResolveOp) global_resolve, JS_ConvertStub, NULL @@ -4503,7 +4508,7 @@ env_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, static JSClass env_class = { "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, env_setProperty, env_enumerate, (JSResolveOp) env_resolve, JS_ConvertStub @@ -4602,7 +4607,7 @@ static JSFunctionSpec dom_methods[] = { static JSClass dom_class = { "FakeDOMObject", JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/tests/ecma_5/Array/reverse-order-of-low-high-accesses.js b/js/src/tests/ecma_5/Array/reverse-order-of-low-high-accesses.js new file mode 100644 index 000000000000..a9b1e80deb2d --- /dev/null +++ b/js/src/tests/ecma_5/Array/reverse-order-of-low-high-accesses.js @@ -0,0 +1,88 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 858677; +var summary = + "[].reverse should swap elements low to high using accesses to low " + + "elements, then accesses to high elements"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var observed = []; + +// (0, 7) hits the lowerExists/upperExists case. +// (1, 6) hits the !lowerExists/upperExists case. +// (2, 5) hits the lowerExists/!upperExists case. +// (3, 4) hits the !lowerExists/!upperExists case. +// +// It'd be a good idea to have a second version of this test at some point +// where the "array" being reversed is a proxy, to detect proper ordering of +// getproperty, hasproperty, setproperty into a hole, and deleteproperty from a +// non-configurable element. But at present our Array.prototype.reverse +// implementation probably doesn't conform fully to all this (because our +// internal MOP is still slightly off), so punt for now. +var props = + { + 0: { + configurable: true, + get: function() { observed.push("index 0 get"); return "index 0 get"; }, + set: function(v) { observed.push("index 0 set: " + v); } + }, + /* 1: hole */ + 2: { + configurable: true, + get: function() { observed.push("index 2 get"); return "index 2 get"; }, + set: function(v) { observed.push("index 2 set: " + v); } + }, + /* 3: hole */ + /* 4: hole */ + /* 5: hole */ + 6: { + configurable: true, + get: function() { observed.push("index 6 get"); return "index 6 get"; }, + set: function(v) { observed.push("index 6 set: " + v); } + }, + 7: { + configurable: true, + get: function() { observed.push("index 7 get"); return "index 7 get"; }, + set: function(v) { observed.push("index 7 set: " + v); } + }, + }; + +var arr = Object.defineProperties(new Array(8), props); + +arr.reverse(); + +var expectedObserved = + ["index 0 get", "index 7 get", "index 0 set: index 7 get", "index 7 set: index 0 get", + "index 6 get", + "index 2 get" + /* nothing for 3/4 */]; +print(observed); +// Do this before the assertions below futz even more with |observed|. +assertEq(observed.length, expectedObserved.length); +for (var i = 0; i < expectedObserved.length; i++) + assertEq(observed[i], expectedObserved[i]); + +assertEq(arr[0], "index 0 get"); // no deletion, setting doesn't overwrite +assertEq(arr[1], "index 6 get"); // copies result of getter +assertEq(2 in arr, false); // deleted +assertEq(3 in arr, false); // never there +assertEq(4 in arr, false); // never there +assertEq(arr[5], "index 2 get"); // copies result of getter +assertEq(6 in arr, false); // deleted +assertEq(arr[7], "index 7 get"); // no deletion, setter doesn't overwrite + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/test402/HG-INFO b/js/src/tests/test402/HG-INFO new file mode 100644 index 000000000000..50ef8efc055b --- /dev/null +++ b/js/src/tests/test402/HG-INFO @@ -0,0 +1,7 @@ +URL: http://hg.ecmascript.org/tests/test262 +changeset: 363:4f586032baec +tag: tip +user: Norbert Lindenberg +date: Sun Mar 24 23:48:59 2013 -0700 +summary: New tests and test fixes for ECMAScript Internationalization API. + diff --git a/js/src/tests/test402/LICENSE b/js/src/tests/test402/LICENSE new file mode 100644 index 000000000000..46b55a37b3e4 --- /dev/null +++ b/js/src/tests/test402/LICENSE @@ -0,0 +1,28 @@ +The << Software identified by reference to the Ecma Standard* ("Software)">> is protected by copyright and is being +made available under the "BSD License", included below. This Software may be subject to third party rights (rights +from parties other than Ecma International), including patent rights, and no licenses under such third party rights +are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA +CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR +INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*. + +Copyright (C) 2012-2013 Ecma International +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +* Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports \ No newline at end of file diff --git a/js/src/tests/test402/ch06/6.2/6.2.2_a.js b/js/src/tests/test402/ch06/6.2/6.2.2_a.js new file mode 100644 index 000000000000..a56894570b2c --- /dev/null +++ b/js/src/tests/test402/ch06/6.2/6.2.2_a.js @@ -0,0 +1,40 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that structurally valid language tags are accepted. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var validLanguageTags = [ + "de", // ISO 639 language code + "de-DE", // + ISO 3166-1 country code + "DE-de", // tags are case-insensitive + "cmn", // ISO 639 language code + "cmn-Hans", // + script code + "CMN-hANS", // tags are case-insensitive + "cmn-hans-cn", // + ISO 3166-1 country code + "es-419", // + UN M.49 region code + "es-419-u-nu-latn-cu-bob", // + Unicode locale extension sequence + "i-klingon", // grandfathered tag + "cmn-hans-cn-t-ca-u-ca-x-t-u", // singleton subtags can also be used as private use subtags + "enochian-enochian", // language and variant subtags may be the same + "de-gregory-u-ca-gregory", // variant and extension subtags may be the same + "aa-a-foo-x-a-foo-bar", // variant subtags can also be used as private use subtags + "x-en-US-12345", // anything goes in private use tags + "x-12345-12345-en-US", + "x-en-US-12345-12345", + "x-en-u-foo", + "x-en-u-foo-u-bar" +]; + +testWithIntlConstructors(function (Constructor) { + validLanguageTags.forEach(function (tag) { + // this must not throw an exception for a valid language tag + var obj = new Constructor([tag]); + }); + return true; +}); + diff --git a/js/src/tests/test402/ch06/6.2/6.2.2_b.js b/js/src/tests/test402/ch06/6.2/6.2.2_b.js new file mode 100644 index 000000000000..42d69e7c2e0f --- /dev/null +++ b/js/src/tests/test402/ch06/6.2/6.2.2_b.js @@ -0,0 +1,41 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that language tags with "_" are not accepted. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var invalidLanguageTags = [ + "de_DE", + "DE_de", + "cmn_Hans", + "cmn-hans_cn", + "es_419", + "es-419-u-nu-latn-cu_bob", + "i_klingon", + "cmn-hans-cn-t-ca-u-ca-x_t-u", + "enochian_enochian", + "de-gregory_u-ca-gregory" +]; + +testWithIntlConstructors(function (Constructor) { + invalidLanguageTags.forEach(function (tag) { + var error; + try { + // this must throw an exception for an invalid language tag + var obj = new Constructor([tag]); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid language tag " + tag + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid language tag " + tag + " was rejected with wrong error " + error.name + "."); + } + }); + return true; +}); + diff --git a/js/src/tests/test402/ch06/6.2/6.2.2_c.js b/js/src/tests/test402/ch06/6.2/6.2.2_c.js new file mode 100644 index 000000000000..6d669ebefdff --- /dev/null +++ b/js/src/tests/test402/ch06/6.2/6.2.2_c.js @@ -0,0 +1,47 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that language tags with invalid subtag sequences are not accepted. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var invalidLanguageTags = [ + "", // empty tag + "i", // singleton alone + "x", // private use without subtag + "u", // extension singleton in first place + "419", // region code in first place + "u-nu-latn-cu-bob", // extension sequence without language + "hans-cmn-cn", // "hans" could theoretically be a 4-letter language code, + // but those can't be followed by extlang codes. + "cmn-hans-cn-u-u", // duplicate singleton + "cmn-hans-cn-t-u-ca-u", // duplicate singleton + "de-gregory-gregory", // duplicate variant + "*", // language range + "de-*", // language range + "中文", // non-ASCII letters + "en-ß", // non-ASCII letters + "ıd" // non-ASCII letters +]; + +testWithIntlConstructors(function (Constructor) { + invalidLanguageTags.forEach(function (tag) { + var error; + try { + // this must throw an exception for an invalid language tag + var obj = new Constructor([tag]); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid language tag " + tag + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid language tag " + tag + " was rejected with wrong error " + error.name + "."); + } + }); + return true; +}); + diff --git a/js/src/tests/test402/ch06/6.2/6.2.3.js b/js/src/tests/test402/ch06/6.2/6.2.3.js new file mode 100644 index 000000000000..4ae15ab271c1 --- /dev/null +++ b/js/src/tests/test402/ch06/6.2/6.2.3.js @@ -0,0 +1,69 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that language tags are canonicalized in return values. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var canonicalizedTags = { + "de": ["de"], + "de-DE": ["de-DE", "de"], + "DE-de": ["de-DE", "de"], + "cmn": ["cmn"], + "CMN-hANS": ["cmn-Hans", "cmn"], + "cmn-hans-cn": ["cmn-Hans-CN", "cmn-Hans", "cmn"], + "es-419": ["es-419", "es"], + "es-419-u-nu-latn": ["es-419-u-nu-latn", "es-419", "es", "es-u-nu-latn"], + // -u-ca is incomplete, so it will not show up in resolvedOptions().locale + "cmn-hans-cn-u-ca-t-ca-x-t-u": ["cmn-Hans-CN-t-ca-u-ca-x-t-u", "cmn-Hans-CN-t-ca-x-t-u", "cmn-Hans-CN-t-ca-x-t", "cmn-Hans-CN-t-ca", "cmn-Hans-CN", "cmn-Hans", "cmn"], + "enochian-enochian": ["enochian-enochian", "enochian"], + "de-gregory-u-ca-gregory": ["de-gregory-u-ca-gregory", "de-gregory", "de-u-ca-gregory", "de"], + "no-nyn": ["nn"], + "i-klingon": ["tlh"], + "sgn-GR": ["gss"], + "ji": ["yi"], + "de-DD": ["de-DE", "de"], + "zh-hak-CN": ["hak-CN", "hak"], + "sgn-ils": ["ils"], + "in": ["id"], + "x-foo": ["x-foo"] +}; + +// make sure the data above is correct +Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) { + canonicalizedTags[tag].forEach(function (canonicalTag) { + if (!isCanonicalizedStructurallyValidLanguageTag(canonicalTag)) { + $ERROR("Test data \"" + canonicalTag + "\" is not canonicalized and structurally valid language tag."); + } + }); +}); + +// now the actual test +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + Object.getOwnPropertyNames(canonicalizedTags).forEach(function (tag) { + // use lookup locale matcher to keep the set of possible return values predictable + + // Variant 1: construct an object and see whether its locale is canonicalized. + // In this variant, shortened forms or the default locale may be returned + var object = new Constructor([tag], {localeMatcher: "lookup"}); + var locale = object.resolvedOptions().locale; + if (canonicalizedTags[tag].indexOf(locale) === -1 && locale !== defaultLocale) { + $ERROR("For " + tag + " got " + locale + "; expected one of " + + canonicalizedTags[tag].join(", ") + "."); + } + + // Variant 2: get the supported locales. If the tag is supported, it should be returned canonicalized but unshortened + var supported = Constructor.supportedLocalesOf([tag]); + if (supported.length > 0 && supported[0] !== canonicalizedTags[tag][0]) { + $ERROR("For " + tag + " got " + supported[0] + "; expected " + + canonicalizedTags[tag][0] + "."); + } + }); + return true; +}); + diff --git a/js/src/tests/test402/ch06/6.2/6.2.4.js b/js/src/tests/test402/ch06/6.2/6.2.4.js new file mode 100644 index 000000000000..6ca47af14265 --- /dev/null +++ b/js/src/tests/test402/ch06/6.2/6.2.4.js @@ -0,0 +1,19 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the default locale is a String value representing the + * structurally valid and canonicalized BCP 47 language tag. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + if (!isCanonicalizedStructurallyValidLanguageTag(defaultLocale)) { + $ERROR("Default locale \"" + defaultLocale + "\" is not canonicalized and structurally valid language tag."); + } + return true; +}); + diff --git a/js/src/tests/test402/ch06/6.2/browser.js b/js/src/tests/test402/ch06/6.2/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/6.2/shell.js b/js/src/tests/test402/ch06/6.2/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/6.3/6.3.1_a.js b/js/src/tests/test402/ch06/6.3/6.3.1_a.js new file mode 100644 index 000000000000..01cc18b0306b --- /dev/null +++ b/js/src/tests/test402/ch06/6.3/6.3.1_a.js @@ -0,0 +1,25 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that well-formed currency codes are accepted. + * @author Norbert Lindenberg + */ + +var wellFormedCurrencyCodes = [ + "BOB", + "EUR", + "usd", // currency codes are case-insensitive + "XdR", + "xTs" +]; + +wellFormedCurrencyCodes.forEach(function (code) { + // this must not throw an exception for a valid currency code + var format = new Intl.NumberFormat(["de-de"], {style: "currency", currency: code}); + if (format.resolvedOptions().currency !== code.toUpperCase()) { + $ERROR("Currency " + code + " was not correctly accepted; turned into " + + format.resolvedOptions().currency + "."); + } +}); + diff --git a/js/src/tests/test402/ch06/6.3/6.3.1_b.js b/js/src/tests/test402/ch06/6.3/6.3.1_b.js new file mode 100644 index 000000000000..038dd1fc4a6c --- /dev/null +++ b/js/src/tests/test402/ch06/6.3/6.3.1_b.js @@ -0,0 +1,35 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that invalid currency codes are not accepted. + * @author Norbert Lindenberg + */ + +var invalidCurrencyCodes = [ + "", + "€", + "$", + "SFr.", + "DM", + "KR₩", + "702", + "ßP", + "ınr" +]; + +invalidCurrencyCodes.forEach(function (code) { + var error; + try { + // this must throw an exception for an invalid currency code + var format = new Intl.NumberFormat(["de-de"], {style: "currency", currency: code}); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid currency code '" + code + "' was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid currency code '" + code + "' was rejected with wrong error " + error.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch06/6.3/browser.js b/js/src/tests/test402/ch06/6.3/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/6.3/shell.js b/js/src/tests/test402/ch06/6.3/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/6.4/6.4_a.js b/js/src/tests/test402/ch06/6.4/6.4_a.js new file mode 100644 index 000000000000..05202353c05d --- /dev/null +++ b/js/src/tests/test402/ch06/6.4/6.4_a.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that valid time zone names are accepted. + * @author Norbert Lindenberg + */ + +var validTimeZoneNames = [ + "UTC", + "utc" // time zone names are case-insensitive +]; + +validTimeZoneNames.forEach(function (name) { + // this must not throw an exception for a valid time zone name + var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name}); + if (format.resolvedOptions().timeZone !== name.toUpperCase()) { + $ERROR("Time zone name " + name + " was not correctly accepted; turned into " + + format.resolvedOptions().timeZone + "."); + } +}); + diff --git a/js/src/tests/test402/ch06/6.4/6.4_b.js b/js/src/tests/test402/ch06/6.4/6.4_b.js new file mode 100644 index 000000000000..847d804e3c8b --- /dev/null +++ b/js/src/tests/test402/ch06/6.4/6.4_b.js @@ -0,0 +1,34 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that invalid time zone names are not accepted. + * @author Norbert Lindenberg + */ + +var invalidTimeZoneNames = [ + "", + "MEZ", // localized abbreviation + "Pacific Time", // localized long form + "cnsha", // BCP 47 time zone code + "invalid", // as the name says + "Europe/İstanbul", // non-ASCII letter + "asıa/baku", // non-ASCII letter + "europe/brußels" // non-ASCII letter +]; + +invalidTimeZoneNames.forEach(function (name) { + var error; + try { + // this must throw an exception for an invalid time zone name + var format = new Intl.DateTimeFormat(["de-de"], {timeZone: name}); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid time zone name " + name + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid time zone name " + name + " was rejected with wrong error " + error.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch06/6.4/6.4_c.js b/js/src/tests/test402/ch06/6.4/6.4_c.js new file mode 100644 index 000000000000..a9969b648598 --- /dev/null +++ b/js/src/tests/test402/ch06/6.4/6.4_c.js @@ -0,0 +1,36 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that additional time zone names, if accepted, are handled correctly. + * @author Norbert Lindenberg + */ + +// canonicalization specified in conformance clause +var additionalTimeZoneNames = { + "Etc/GMT": "UTC", + "Greenwich": "UTC", + "PRC": "Asia/Shanghai", + "AmErIcA/LoS_aNgElEs": "America/Los_Angeles", + "etc/gmt+7": "Etc/GMT+7" +}; + +Object.getOwnPropertyNames(additionalTimeZoneNames).forEach(function (name) { + var format, error; + try { + format = new Intl.DateTimeFormat([], {timeZone: name}); + } catch (e) { + error = e; + } + if (error === undefined) { + var actual = format.resolvedOptions().timeZone; + var expected = additionalTimeZoneNames[name]; + if (actual !== expected) { + $ERROR("Time zone name " + name + " was accepted, but incorrectly canonicalized to " + + actual + "; expected " + expected + "."); + } + } else if (error.name !== "RangeError") { + $ERROR("Time zone name " + name + " was rejected with wrong error " + error.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch06/6.4/browser.js b/js/src/tests/test402/ch06/6.4/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/6.4/shell.js b/js/src/tests/test402/ch06/6.4/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/browser.js b/js/src/tests/test402/ch06/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch06/shell.js b/js/src/tests/test402/ch06/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch08/8.0/8.0.js b/js/src/tests/test402/ch08/8.0/8.0.js new file mode 100644 index 000000000000..dedda973b206 --- /dev/null +++ b/js/src/tests/test402/ch08/8.0/8.0.js @@ -0,0 +1,12 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl has Object.prototype as its prototype. + * @author Norbert Lindenberg + */ + +if (Object.getPrototypeOf(Intl) !== Object.prototype) { + $ERROR("Intl doesn't have Object.prototype as its prototype."); +} + diff --git a/js/src/tests/test402/ch08/8.0/8.0_L15.js b/js/src/tests/test402/ch08/8.0/8.0_L15.js new file mode 100644 index 000000000000..0174bef54e57 --- /dev/null +++ b/js/src/tests/test402/ch08/8.0/8.0_L15.js @@ -0,0 +1,15 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(fnGlobalObject().Intl, false, false, []); +testBuiltInObject(Intl, false, false, ["Collator", "NumberFormat", "DateTimeFormat"]); + diff --git a/js/src/tests/test402/ch08/8.0/browser.js b/js/src/tests/test402/ch08/8.0/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch08/8.0/shell.js b/js/src/tests/test402/ch08/8.0/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch08/browser.js b/js/src/tests/test402/ch08/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch08/shell.js b/js/src/tests/test402/ch08/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch09/9.1/9.1_a.js b/js/src/tests/test402/ch09/9.1/9.1_a.js new file mode 100644 index 000000000000..b7358304bb63 --- /dev/null +++ b/js/src/tests/test402/ch09/9.1/9.1_a.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that default locale is available. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + var supportedLocales = Constructor.supportedLocalesOf([defaultLocale]); + if (supportedLocales.indexOf(defaultLocale) === -1) { + $ERROR("Default locale is not reported as available."); + } +}); + diff --git a/js/src/tests/test402/ch09/9.1/9.1_b.js b/js/src/tests/test402/ch09/9.1/9.1_b.js new file mode 100644 index 000000000000..a0abc7fc1400 --- /dev/null +++ b/js/src/tests/test402/ch09/9.1/9.1_b.js @@ -0,0 +1,32 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that appropriate fallback locales are provided for + * supported locales. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var info = getLocaleSupportInfo(Constructor); + var fallback; + info.supported.forEach(function (locale) { + var pos = locale.lastIndexOf("-"); + if (pos !== -1) { + fallback = locale.substring(0, pos); + if (info.supported.indexOf(fallback) === -1) { + $ERROR("Locale " + locale + " is supported, but fallback " + fallback + " isn't."); + } + } + var match = /([a-z]{2,3})(-[A-Z][a-z]{3})(-[A-Z]{2})/.exec(locale); + if (match !== null) { + fallback = match[1] + match[3]; + if (info.supported.indexOf(fallback) === -1) { + $ERROR("Locale " + locale + " is supported, but fallback " + fallback + " isn't."); + } + } + }); +}); + diff --git a/js/src/tests/test402/ch09/9.1/browser.js b/js/src/tests/test402/ch09/9.1/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch09/9.1/shell.js b/js/src/tests/test402/ch09/9.1/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch09/9.2/9.2.1_1.js b/js/src/tests/test402/ch09/9.2/9.2.1_1.js new file mode 100644 index 000000000000..7386fdeda0dc --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.1_1.js @@ -0,0 +1,23 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that canonicalization of locale lists treats undefined and empty lists the same. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var supportedForUndefined = Constructor.supportedLocalesOf(undefined); + var supportedForEmptyList = Constructor.supportedLocalesOf([]); + if (supportedForUndefined.length !== supportedForEmptyList.length) { + $ERROR("Supported locales differ between undefined and empty list input."); + } + // we don't compare the elements because length should be 0 - let's just verify that + if (supportedForUndefined.length !== 0) { + $ERROR("Internal test error: Assumption about length being 0 is invalid."); + } + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.1_2.js b/js/src/tests/test402/ch09/9.2/9.2.1_2.js new file mode 100644 index 000000000000..e4fb3756dbb7 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.1_2.js @@ -0,0 +1,21 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a List is not affected by adversarial + * changes to Array.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintArray(); + +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + var canonicalized = Constructor.supportedLocalesOf([defaultLocale, defaultLocale]); + if (canonicalized.length > 1) { + $ERROR("Canonicalization didn't remove duplicate language tags from locale list."); + } +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.1_3.js b/js/src/tests/test402/ch09/9.2/9.2.1_3.js new file mode 100644 index 000000000000..e403b17653eb --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.1_3.js @@ -0,0 +1,87 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that a single string instead of a locale list is treated + * as the locale list containing that string. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var validAndInvalidLanguageTags = [ + "de", // ISO 639 language code + "de-DE", // + ISO 3166-1 country code + "DE-de", // tags are case-insensitive + "cmn", // ISO 639 language code + "cmn-Hans", // + script code + "CMN-hANS", // tags are case-insensitive + "cmn-hans-cn", // + ISO 3166-1 country code + "es-419", // + UN M.49 region code + "es-419-u-nu-latn-cu-bob", // + Unicode locale extension sequence + "i-klingon", // grandfathered tag + "cmn-hans-cn-t-ca-u-ca-x-t-u", // singleton subtags can also be used as private use subtags + "enochian-enochian", // language and variant subtags may be the same + "de-gregory-u-ca-gregory", // variant and extension subtags may be the same + "de_DE", + "DE_de", + "cmn_Hans", + "cmn-hans_cn", + "es_419", + "es-419-u-nu-latn-cu_bob", + "i_klingon", + "cmn-hans-cn-t-ca-u-ca-x_t-u", + "enochian_enochian", + "de-gregory_u-ca-gregory", + "i", // singleton alone + "x", // private use without subtag + "u", // extension singleton in first place + "419", // region code in first place + "u-nu-latn-cu-bob", // extension sequence without language + "hans-cmn-cn", // "hans" could theoretically be a 4-letter language code, + // but those can't be followed by extlang codes. + "cmn-hans-cn-u-u", // duplicate singleton + "cmn-hans-cn-t-u-ca-u", // duplicate singleton + "de-gregory-gregory" // duplicate variant +]; + +testWithIntlConstructors(function (Constructor) { + validAndInvalidLanguageTags.forEach(function (locale) { + var obj1, obj2, locale1, locale2, error1, error2; + try { + obj1 = new Constructor(locale); + locale1 = obj1.resolvedOptions().locale; + } catch (e) { + error1 = e; + } + try { + obj2 = new Constructor([locale]); + locale2 = obj2.resolvedOptions().locale; + } catch (e) { + error2 = e; + } + + if ((error1 === undefined) !== (error2 === undefined)) { + if (error1 === undefined) { + $ERROR("Single locale string " + locale + + " was accepted, but locale list containing that string wasn't."); + } else { + $ERROR("Single locale string " + locale + + " was rejected, but locale list containing that string wasn't."); + } + } else if (error1 === undefined) { + if (locale1 !== locale2) { + $ERROR("Single locale string " + locale + " results in " + locale1 + + ", but locale list [" + locale + "] results in " + locale2 + "."); + } + } else { + if (error1.name !== error2.name) { + $ERROR("Single locale string " + locale + " results in error " + error1.name + + ", but locale list [" + locale + "] results in error " + error2.name + "."); + } + } + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.1_4.js b/js/src/tests/test402/ch09/9.2/9.2.1_4.js new file mode 100644 index 000000000000..b9bb9db79d47 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.1_4.js @@ -0,0 +1,46 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that non-objects are converted to objects before canonicalization. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + // undefined is handled separately + + // null should result in a TypeError + var error; + try { + var supportedForNull = Constructor.supportedLocalesOf(null); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Null as locale list was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Null as locale list was rejected with wrong error " + error.name + "."); + } + + // let's use an empty list for comparison + var supportedForEmptyList = Constructor.supportedLocalesOf([]); + // we don't compare the elements because length should be 0 - let's just verify that + if (supportedForEmptyList.length !== 0) { + $ERROR("Internal test error: Assumption about length being 0 is invalid."); + } + + // most non-objects will be interpreted as empty lists because a missing length property is interpreted as 0 + var supportedForNumber = Constructor.supportedLocalesOf(5); + if (supportedForNumber.length !== supportedForEmptyList.length) { + $ERROR("Supported locales differ between numeric and empty list input."); + } + var supportedForBoolean = Constructor.supportedLocalesOf(true); + if (supportedForBoolean.length !== supportedForEmptyList.length) { + $ERROR("Supported locales differ between boolean and empty list input."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.1_8_c_ii.js b/js/src/tests/test402/ch09/9.2/9.2.1_8_c_ii.js new file mode 100644 index 000000000000..8dfb9b7b377f --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.1_8_c_ii.js @@ -0,0 +1,30 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that values other than strings are not accepted as locales. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var notStringOrObject = [undefined, null, true, false, 0, 5, -5, NaN]; + +testWithIntlConstructors(function (Constructor) { + notStringOrObject.forEach(function (value) { + var error; + try { + var supported = Constructor.supportedLocalesOf([value]); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("" + value + " as locale was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("" + value + " as locale was rejected with wrong error " + error.name + "."); + } + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.1_8_c_vi.js b/js/src/tests/test402/ch09/9.2/9.2.1_8_c_vi.js new file mode 100644 index 000000000000..ef78fa97b0c1 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.1_8_c_vi.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that canonicalization of locale lists removes duplicate language tags. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + var canonicalized = Constructor.supportedLocalesOf([defaultLocale, defaultLocale]); + if (canonicalized.length > 1) { + $ERROR("Canonicalization didn't remove duplicate language tags from locale list."); + } +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.2.js b/js/src/tests/test402/ch09/9.2/9.2.2.js new file mode 100644 index 000000000000..cb74eaad2a53 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.2.js @@ -0,0 +1,45 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that locales that are reported by resolvedOptions + * are also reported by supportedLocalesOf. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var info = getLocaleSupportInfo(Constructor); + // this test should work equally for both matching algorithms + ["lookup", "best fit"].forEach(function (matcher) { + var supportedByConstructor = info.supported.concat(info.byFallback); + var supported = Constructor.supportedLocalesOf(supportedByConstructor, + {localeMatcher: matcher}); + // we could check the length first, but it's probably more interesting which locales are missing + var i = 0; + var limit = Math.min(supportedByConstructor.length, supported.length); + while (i < limit && supportedByConstructor[i] === supported[i]) { + i++; + } + if (i < supportedByConstructor.length) { + $ERROR("Locale " + supportedByConstructor[i] + + " is returned by resolvedOptions but not by supportedLocalesOf."); + } else if (i < supported.length) { + $ERROR("Locale " + supported[i] + + " is returned by supportedLocalesOf but not by resolvedOptions."); + } + }); + + // this test is only valid for lookup - best fit may find additional locales supported + var unsupportedByConstructor = info.unsupported; + var supported = Constructor.supportedLocalesOf(unsupportedByConstructor, + {localeMatcher: "lookup"}); + if (supported.length > 0) { + $ERROR("Locale " + supported[0] + + " is returned by supportedLocalesOf but not by resolvedOptions."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.3_5.js b/js/src/tests/test402/ch09/9.2/9.2.3_5.js new file mode 100644 index 000000000000..8ae8a216b630 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.3_5.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["locale", "extension", "extensionIndex"]); + +testWithIntlConstructors(function (Constructor) { + var locale = new Constructor(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; + if (!isCanonicalizedStructurallyValidLanguageTag(locale)) { + $ERROR("Constructor returns invalid locale " + locale + "."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.5_11_g_ii_2.js b/js/src/tests/test402/ch09/9.2/9.2.5_11_g_ii_2.js new file mode 100644 index 000000000000..d4213d2dae4f --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.5_11_g_ii_2.js @@ -0,0 +1,26 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that missing Unicode extension values default to true for + * boolean keys. + * @author Norbert Lindenberg + */ + +var extensions = ["-u-co-phonebk-kn", "-u-kn-co-phonebk"]; +extensions.forEach(function (extension) { + var defaultLocale = new Intl.Collator().resolvedOptions().locale; + var collator = new Intl.Collator([defaultLocale + extension], {usage: "sort"}); + var locale = collator.resolvedOptions().locale; + var numeric = collator.resolvedOptions().numeric; + if (numeric !== undefined) { + if (numeric !== true) { + $ERROR("Default value for \"kn\" should be true, but is " + numeric + "."); + } + if (locale.indexOf("-kn") !== -1) { + $ERROR("\"kn\" is returned in locale, but shouldn't be."); + } + } +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.5_6.js b/js/src/tests/test402/ch09/9.2/9.2.5_6.js new file mode 100644 index 000000000000..4bc904ee1700 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.5_6.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["dataLocale", "nu", "ca", "co", "locale"]); + +testWithIntlConstructors(function (Constructor) { + var locale = new Constructor(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; + if (!isCanonicalizedStructurallyValidLanguageTag(locale)) { + $ERROR("Constructor returns invalid locale " + locale + "."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.6_2.js b/js/src/tests/test402/ch09/9.2/9.2.6_2.js new file mode 100644 index 000000000000..8d4f7efa9b80 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.6_2.js @@ -0,0 +1,27 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a List is not affected by adversarial + * changes to Array.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintArray(); + +testWithIntlConstructors(function (Constructor) { + // this test should work equally for both matching algorithms + ["lookup", "best fit"].forEach(function (matcher) { + var defaultLocale = new Constructor().resolvedOptions().locale; + var canonicalized = Constructor.supportedLocalesOf([defaultLocale, defaultLocale], + {localeMatcher: matcher}); + if (canonicalized.length > 1) { + $ERROR("Canonicalization with matcher " + matcher + " didn't remove duplicate language tags from locale list."); + } + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.6_4.js b/js/src/tests/test402/ch09/9.2/9.2.6_4.js new file mode 100644 index 000000000000..7c053a381db4 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.6_4.js @@ -0,0 +1,23 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that LookupSupportedLocales returns an empty list when + * given an empty list. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + // this test should work equally for both matching algorithms + ["lookup", "best fit"].forEach(function (matcher) { + var supported = Constructor.supportedLocalesOf([], {localeMatcher: matcher}); + if (supported.length !== 0) { + $ERROR("SupportedLocales with matcher " + matcher + " returned a non-empty list for an empty list."); + } + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.6_4_b.js b/js/src/tests/test402/ch09/9.2/9.2.6_4_b.js new file mode 100644 index 000000000000..5b9a43157afa --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.6_4_b.js @@ -0,0 +1,47 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Unicode locale extension sequences do not affect + * whether a locale is considered supported, but are reported back. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + // this test should work equally for both matching algorithms + ["lookup", "best fit"].forEach(function (matcher) { + var info = getLocaleSupportInfo(Constructor); + var allLocales = info.supported.concat(info.byFallback, info.unsupported); + allLocales.forEach(function (locale) { + var validExtension = "-u-co-phonebk-nu-latn"; + var invalidExtension = "-u-nu-invalid"; + var supported1 = Constructor.supportedLocalesOf([locale], + {localeMatcher: matcher}); + var supported2 = Constructor.supportedLocalesOf([locale + validExtension], + {localeMatcher: matcher}); + var supported3 = Constructor.supportedLocalesOf([locale + invalidExtension], + {localeMatcher: matcher}); + if (supported1.length === 1) { + if (supported2.length !== 1 || supported3.length !== 1) { + $ERROR("Presence of Unicode locale extension sequence affects whether locale " + + locale + " is considered supported with matcher " + matcher + "."); + } + if (supported2[0] !== locale + validExtension || supported3[0] !== locale + invalidExtension) { + alert(locale + "; " + supported2[0] + "; " + supported3[0]); + $ERROR("Unicode locale extension sequence is not correctly returned for locale " + + locale + " with matcher " + matcher + "."); + } + } else { + if (supported2.length !== 0 || supported3.length !== 0) { + $ERROR("Presence of Unicode locale extension sequence affects whether locale " + + locale + " is considered supported with matcher " + matcher + "."); + } + } + }); + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.6_4_c.js b/js/src/tests/test402/ch09/9.2/9.2.6_4_c.js new file mode 100644 index 000000000000..de68a9b6643d --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.6_4_c.js @@ -0,0 +1,32 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that LookupSupportedLocales includes the default locale + * and doesn't include the "no linguistic content" locale. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + // this test should work equally for both matching algorithms + ["lookup", "best fit"].forEach(function (matcher) { + var defaultLocale = new Constructor().resolvedOptions().locale; + var noLinguisticContent = "zxx"; + var supported = Constructor.supportedLocalesOf([defaultLocale, noLinguisticContent], + {localeMatcher: matcher}); + if (supported.indexOf(defaultLocale) === -1) { + $ERROR("SupportedLocales didn't return default locale with matcher " + matcher + "."); + } + if (supported.indexOf(noLinguisticContent) !== -1) { + $ERROR("SupportedLocales returned the \"no linguistic content\" locale with matcher " + matcher + "."); + } + if (supported.length > 1) { + $ERROR("SupportedLocales returned stray locales: " + supported.join(", ") + " with matcher " + matcher + "."); + } + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.8_1_c.js b/js/src/tests/test402/ch09/9.2/9.2.8_1_c.js new file mode 100644 index 000000000000..724db1edd18d --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.8_1_c.js @@ -0,0 +1,36 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option localeMatcher is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + + var validValues = [undefined, "lookup", "best fit", {toString: function () { return "lookup"; }}]; + validValues.forEach(function (value) { + var supported = Constructor.supportedLocalesOf([defaultLocale], {localeMatcher: value}); + }); + + var invalidValues = [null, 0, 5, NaN, true, false, "invalid"]; + invalidValues.forEach(function (value) { + var error; + try { + var supported = Constructor.supportedLocalesOf([defaultLocale], {localeMatcher: value}); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid localeMatcher value " + value + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid localeMatcher value " + value + " was rejected with wrong error " + error.name + "."); + } + }); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/9.2.8_4.js b/js/src/tests/test402/ch09/9.2/9.2.8_4.js new file mode 100644 index 000000000000..79c362f62125 --- /dev/null +++ b/js/src/tests/test402/ch09/9.2/9.2.8_4.js @@ -0,0 +1,35 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the array returned by SupportedLocales is extensible, + * but its properties are non-writable/non-configurable. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +function testFrozenProperty(obj, property) { + var desc = Object.getOwnPropertyDescriptor(obj, property); + if (desc.writable) { + $ERROR("Property " + property + " of object returned by SupportedLocales is writable."); + } + if (desc.configurable) { + $ERROR("Property " + property + " of object returned by SupportedLocales is configurable."); + } +} + +testWithIntlConstructors(function (Constructor) { + var defaultLocale = new Constructor().resolvedOptions().locale; + var supported = Constructor.supportedLocalesOf([defaultLocale]); + if (!Object.isExtensible(supported)) { + $ERROR("Object returned by SupportedLocales is not extensible."); + } + for (var i = 0; i < supported.length; i++) { + testFrozenProperty(supported, i); + } + testFrozenProperty(supported, "length"); + + return true; +}); + diff --git a/js/src/tests/test402/ch09/9.2/browser.js b/js/src/tests/test402/ch09/9.2/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch09/9.2/shell.js b/js/src/tests/test402/ch09/9.2/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch09/browser.js b/js/src/tests/test402/ch09/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch09/shell.js b/js/src/tests/test402/ch09/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_1.js b/js/src/tests/test402/ch10/10.1/10.1.1_1.js new file mode 100644 index 000000000000..432e073fc5d2 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_1.js @@ -0,0 +1,43 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that an object can't be re-initialized as a Collator. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var obj, error; + + // variant 1: use constructor in a "new" expression + obj = new Constructor(); + try { + Intl.Collator.call(obj); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Re-initializing object created with \"new\" as Collator was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Re-initializing object created with \"new\" as Collator was rejected with wrong error " + error.name + "."); + } + + // variant 2: use constructor as a function + obj = Constructor.call({}); + error = undefined; + try { + Intl.Collator.call(obj); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Re-initializing object created with constructor as function as Collator was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Re-initializing object created with constructor as function as Collator was rejected with wrong error " + error.name + "."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_10.js b/js/src/tests/test402/ch10/10.1/10.1.1_10.js new file mode 100644 index 000000000000..5c6b657b5977 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_10.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["localeMatcher", "kn", "kf"]); + +var locale = new Intl.Collator(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +if (!isCanonicalizedStructurallyValidLanguageTag(locale)) { + $ERROR("Collator returns invalid locale " + locale + "."); +} + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_11.js b/js/src/tests/test402/ch10/10.1/10.1.1_11.js new file mode 100644 index 000000000000..447fd8b2854a --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_11.js @@ -0,0 +1,12 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option localeMatcher is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.Collator, "localeMatcher", "string", ["lookup", "best fit"], "best fit", {noReturn: true}); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_13.js b/js/src/tests/test402/ch10/10.1/10.1.1_13.js new file mode 100644 index 000000000000..4129eebd2e44 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_13.js @@ -0,0 +1,13 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the options numeric and caseFirst are processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.Collator, "numeric", "boolean", undefined, undefined, {isOptional: true}); +testOption(Intl.Collator, "caseFirst", "string", ["upper", "lower", "false"], undefined, {isOptional: true}); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_19_b.js b/js/src/tests/test402/ch10/10.1/10.1.1_19_b.js new file mode 100644 index 000000000000..f1fef270440b --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_19_b.js @@ -0,0 +1,44 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests the special handling of the "co" key in Intl.Collator. + * @author Norbert Lindenberg + */ + +function checkCollation(extensionCoValue, usageValue, expectedCollations, expectedUsage) { + var requestLocale = extensionCoValue !== undefined ? "de-DE-u-co-" + extensionCoValue : "de-DE"; + var options = usageValue !== undefined ? { usage: usageValue } : undefined; + var collator = new Intl.Collator([requestLocale], options); + + var collation = collator.resolvedOptions().collation; + if (expectedCollations.indexOf(collation) === -1) { + $ERROR((extensionCoValue === undefined ? "Default collation" : "Collation for \"" + extensionCoValue) + + "\" should be " + expectedCollations.join(" or ") + ", but is " + collation + "."); + } + + var usage = collator.resolvedOptions().usage; + if (expectedUsage !== usage) { + $ERROR((usageValue === undefined ? "Default usage" : "Usage") + + " should be " + expectedUsage + ", but is " + usage + "."); + } +} + +checkCollation(undefined, undefined, ["default"], "sort"); + +checkCollation("phonebk", undefined, ["phonebk", "default"], "sort"); + +checkCollation("invalid", undefined, ["default"], "sort"); + +checkCollation("standard", undefined, ["default"], "sort"); + +checkCollation("standard", "search", ["default"], "search"); + +checkCollation("standard", "sort", ["default"], "sort"); + +checkCollation("search", undefined, ["default"], "sort"); + +checkCollation("search", "search", ["default"], "search"); + +checkCollation("search", "sort", ["default"], "sort"); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_19_c.js b/js/src/tests/test402/ch10/10.1/10.1.1_19_c.js new file mode 100644 index 000000000000..4ad76d45bf7a --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_19_c.js @@ -0,0 +1,63 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the options numeric and caseFirst can be + * set through either the locale or the options. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var options = [ + {key: "kn", property: "numeric", type: "boolean", values: [true, false]}, + {key: "kf", property: "caseFirst", type: "string", values: ["upper", "lower", "false"]} +]; + +options.forEach(function (option) { + var defaultLocale = new Intl.Collator().resolvedOptions().locale; + var collator, opt, result; + + // find out which values are supported for a property in the default locale + var supportedValues = []; + option.values.forEach(function (value) { + opt = {}; + opt[option.property] = value; + collator = new Intl.Collator([defaultLocale], opt); + result = collator.resolvedOptions()[option.property]; + if (result !== undefined && supportedValues.indexOf(result) === -1) { + supportedValues.push(result); + } + }); + + // verify that the supported values can also be set through the locale + supportedValues.forEach(function (value) { + collator = new Intl.Collator([defaultLocale + "-u-" + option.key + "-" + value]); + result = collator.resolvedOptions()[option.property]; + if (result !== value) { + $ERROR("Property " + option.property + " couldn't be set through locale extension key " + + option.key + "; requested value: " + value + "; actual value: " + result + "."); + } + }); + + // verify that the options setting overrides the locale setting + supportedValues.forEach(function (value) { + var otherValue; + option.values.forEach(function (possibleValue) { + if (possibleValue !== value) { + otherValue = possibleValue; + } + }); + if (otherValue !== undefined) { + opt = {}; + opt[option.property] = value; + collator = new Intl.Collator([defaultLocale + "-u-" + option.key + "-" + otherValue], opt); + result = collator.resolvedOptions()[option.property]; + if (result !== value) { + $ERROR("Options value for property " + option.property + " doesn't override locale extension key " + + option.key + "; requested value: " + value + "; actual value: " + result + "."); + } + } + }); +}); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_20.js b/js/src/tests/test402/ch10/10.1/10.1.1_20.js new file mode 100644 index 000000000000..97d70c0f957f --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_20.js @@ -0,0 +1,13 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option sensitivity is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// the fallback is variant only for usage === sort, but that happens to be the fallback for usage +testOption(Intl.Collator, "sensitivity", "string", ["base", "accent", "case", "variant"], "variant"); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_23.js b/js/src/tests/test402/ch10/10.1/10.1.1_23.js new file mode 100644 index 000000000000..0b5261509f22 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_23.js @@ -0,0 +1,13 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option ignorePunctuation is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// the fallback is variant only for usage === sort, but that happens to be the fallback for usage +testOption(Intl.Collator, "ignorePunctuation", "boolean", undefined, false); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_6.js b/js/src/tests/test402/ch10/10.1/10.1.1_6.js new file mode 100644 index 000000000000..bc13436d76cc --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_6.js @@ -0,0 +1,12 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option usage is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.Collator, "usage", "string", ["sort", "search"], "sort"); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.1_a.js b/js/src/tests/test402/ch10/10.1/10.1.1_a.js new file mode 100644 index 000000000000..56d4b9789574 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.1_a.js @@ -0,0 +1,14 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that constructing a Collator doesn't create or modify + * unwanted properties on the RegExp constructor. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testForUnwantedRegExpChanges(function () { + new Intl.Collator("de-DE-u-co-phonebk"); +}); diff --git a/js/src/tests/test402/ch10/10.1/10.1.2.1_4.js b/js/src/tests/test402/ch10/10.1/10.1.2.1_4.js new file mode 100644 index 000000000000..22e69065e609 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.2.1_4.js @@ -0,0 +1,21 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that for non-object values passed as this to Collator a + * wrapper object will be initialized and returned. + * @author Norbert Lindenberg + */ + +var thisValues = [true, 42, "国際化"]; + +thisValues.forEach(function (value) { + var collator = Intl.Collator.call(value); + // check that the returned object functions as a collator + var referenceCollator = new Intl.Collator(); + if (Intl.Collator.prototype.compare.call(collator, "a", "b") !== referenceCollator.compare("a", "b")) { + $ERROR("Collator initialized from " + value + " doesn't behave like normal collator."); + } + return true; +}); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.2_a.js b/js/src/tests/test402/ch10/10.1/10.1.2_a.js new file mode 100644 index 000000000000..de69a48093f5 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.2_a.js @@ -0,0 +1,30 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator can be subclassed. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// get a collator and have it sort an array for comparison with the subclass +var locales = ["tlh", "id", "en"]; +var a = ["A", "C", "E", "B", "D", "F"]; +var referenceCollator = new Intl.Collator(locales); +var referenceSorted = a.slice().sort(referenceCollator.compare); + +function MyCollator(locales, options) { + Intl.Collator.call(this, locales, options); + // could initialize MyCollator properties +} + +MyCollator.prototype = Object.create(Intl.Collator.prototype); +MyCollator.prototype.constructor = MyCollator; +// could add methods to MyCollator.prototype + +var collator = new MyCollator(locales); +a.sort(collator.compare); +testArraysAreSame(referenceSorted, a); + diff --git a/js/src/tests/test402/ch10/10.1/10.1.3.js b/js/src/tests/test402/ch10/10.1/10.1.3.js new file mode 100644 index 000000000000..7459d98d6b2b --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1.3.js @@ -0,0 +1,19 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that objects constructed by Intl.Collator have the specified internal properties. + * @author Norbert Lindenberg + */ + +var obj = new Intl.Collator(); + +var actualPrototype = Object.getPrototypeOf(obj); +if (actualPrototype !== Intl.Collator.prototype) { + $ERROR("Prototype of object constructed by Intl.Collator isn't Intl.Collator.prototype; got " + actualPrototype); +} + +if (!Object.isExtensible(obj)) { + $ERROR("Object constructed by Intl.Collator must be extensible."); +} + diff --git a/js/src/tests/test402/ch10/10.1/10.1_L15.js b/js/src/tests/test402/ch10/10.1/10.1_L15.js new file mode 100644 index 000000000000..4dbabfd64637 --- /dev/null +++ b/js/src/tests/test402/ch10/10.1/10.1_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.Collator, true, true, ["supportedLocalesOf"], 0); + diff --git a/js/src/tests/test402/ch10/10.1/browser.js b/js/src/tests/test402/ch10/10.1/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.1/shell.js b/js/src/tests/test402/ch10/10.1/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.2/10.2.1.js b/js/src/tests/test402/ch10/10.2/10.2.1.js new file mode 100644 index 000000000000..9eccb073c45f --- /dev/null +++ b/js/src/tests/test402/ch10/10.2/10.2.1.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.prototype has the required attributes. + * @author Norbert Lindenberg + */ + +var desc = Object.getOwnPropertyDescriptor(Intl.Collator, "prototype"); +if (desc === undefined) { + $ERROR("Intl.Collator.prototype is not defined."); +} +if (desc.writable) { + $ERROR("Intl.Collator.prototype must not be writable."); +} +if (desc.enumerable) { + $ERROR("Intl.Collator.prototype must not be enumerable."); +} +if (desc.configurable) { + $ERROR("Intl.Collator.prototype must not be configurable."); +} + diff --git a/js/src/tests/test402/ch10/10.2/10.2.2_L15.js b/js/src/tests/test402/ch10/10.2/10.2.2_L15.js new file mode 100644 index 000000000000..6ffcdde84da8 --- /dev/null +++ b/js/src/tests/test402/ch10/10.2/10.2.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.supportedLocalesOf + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.Collator.supportedLocalesOf, true, false, [], 1); + diff --git a/js/src/tests/test402/ch10/10.2/10.2.2_a.js b/js/src/tests/test402/ch10/10.2/10.2.2_a.js new file mode 100644 index 000000000000..5cf953ce820e --- /dev/null +++ b/js/src/tests/test402/ch10/10.2/10.2.2_a.js @@ -0,0 +1,27 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator has a supportedLocalesOf + * property, and it works as planned. + */ + +var defaultLocale = new Intl.Collator().resolvedOptions().locale; +var notSupported = 'zxx'; // "no linguistic content" +var requestedLocales = [defaultLocale, notSupported]; + +var supportedLocales; + +if (!Intl.Collator.hasOwnProperty('supportedLocalesOf')) { + $ERROR("Intl.Collator doesn't have a supportedLocalesOf property."); +} + +supportedLocales = Intl.Collator.supportedLocalesOf(requestedLocales); +if (supportedLocales.length !== 1) { + $ERROR('The length of supported locales list is not 1.'); +} + +if (supportedLocales[0] !== defaultLocale) { + $ERROR('The default locale is not returned in the supported list.'); +} + diff --git a/js/src/tests/test402/ch10/10.2/10.2.2_b.js b/js/src/tests/test402/ch10/10.2/10.2.2_b.js new file mode 100644 index 000000000000..1b99fd8c5a3c --- /dev/null +++ b/js/src/tests/test402/ch10/10.2/10.2.2_b.js @@ -0,0 +1,13 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.supportedLocalesOf + * doesn't access arguments that it's not given. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintDataProperty(Object.prototype, "1"); +new Intl.Collator("und"); diff --git a/js/src/tests/test402/ch10/10.2/10.2.3_b.js b/js/src/tests/test402/ch10/10.2/10.2.3_b.js new file mode 100644 index 000000000000..aef1e746a138 --- /dev/null +++ b/js/src/tests/test402/ch10/10.2/10.2.3_b.js @@ -0,0 +1,52 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator does not accept Unicode locale + * extension keys and values that are not allowed. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var testArray = [ + "hello", "你好", "こんにちは", + "pêche", "peché", "1", "9", "10", + "ụ\u031B", "u\u031B\u0323", "ư\u0323", "u\u0323\u031B", + "Å", "Å", "A\u030A" +]; + +var defaultCollator = new Intl.Collator(); +var defaultOptions = defaultCollator.resolvedOptions(); +var defaultOptionsJSON = JSON.stringify(defaultOptions); +var defaultLocale = defaultOptions.locale; +var defaultSortedArray = testArray.slice(0).sort(defaultCollator.compare); + +var keyValues = { + "co": ["standard", "search", "invalid"], + "ka": ["noignore", "shifted", "invalid"], + "kb": ["true", "false", "invalid"], + "kc": ["true", "false", "invalid"], + "kh": ["true", "false", "invalid"], + "kk": ["true", "false", "invalid"], + "kr": ["latn-hira-hani", "hani-hira-latn", "invalid"], + "ks": ["level1", "level2", "level3", "level4", "identic", "invalid"], + "vt": ["1234-5678-9abc-edf0", "invalid"] +}; + +Object.getOwnPropertyNames(keyValues).forEach(function (key) { + keyValues[key].forEach(function (value) { + var collator = new Intl.Collator([defaultLocale + "-u-" + key + "-" + value]); + var options = collator.resolvedOptions(); + if (options.locale !== defaultLocale) { + $ERROR("Locale " + options.locale + " is affected by key " + + key + "; value " + value + "."); + } + if (JSON.stringify(options) !== defaultOptionsJSON) { + $ERROR("Resolved options " + JSON.stringify(options) + " are affected by key " + + key + "; value " + value + "."); + } + testArraysAreSame(defaultSortedArray, testArray.sort(collator.compare)); + }); +}); + diff --git a/js/src/tests/test402/ch10/10.2/browser.js b/js/src/tests/test402/ch10/10.2/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.2/shell.js b/js/src/tests/test402/ch10/10.2/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.3/10.3.1.js b/js/src/tests/test402/ch10/10.3/10.3.1.js new file mode 100644 index 000000000000..699949e18fa9 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.1.js @@ -0,0 +1,13 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.prototype.constructor is the + * Intl.Collator. + */ + +if (Intl.Collator.prototype.constructor !== Intl.Collator) { + $ERROR("Intl.Collator.prototype.constructor is not the same as " + + "Intl.Collator"); +} + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_1_a_L15.js b/js/src/tests/test402/ch10/10.3/10.3.2_1_a_L15.js new file mode 100644 index 000000000000..3d49601db802 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_1_a_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the function returned by Intl.Collator.prototype.compare + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(new Intl.Collator().compare, true, false, [], 2); + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_1_c.js b/js/src/tests/test402/ch10/10.3/10.3.2_1_c.js new file mode 100644 index 000000000000..73f2bcf098c3 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_1_c.js @@ -0,0 +1,36 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that compare function is bound to its Intl.Collator. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var strings = ["d", "O", "od", "oe", "of", "ö", "o\u0308", "X", "y", "Z", "Z.", "𠮷野家", "吉野家", "!A", "A", "b", "C"]; +var locales = [undefined, ["de"], ["de-u-co-phonebk"], ["en"], ["ja"], ["sv"]]; +var options = [ + undefined, + {usage: "search"}, + {sensitivity: "base", ignorePunctuation: true} +]; + +locales.forEach(function (locales) { + options.forEach(function (options) { + var collatorObj = new Intl.Collator(locales, options); + var compareFunc = collatorObj.compare; + var referenceSorted = strings.slice(); + referenceSorted.sort(function (a, b) { return collatorObj.compare(a, b); }); + var sorted = strings; + sorted.sort(compareFunc); + try { + testArraysAreSame(referenceSorted, sorted); + } catch (e) { + e.message += " (Testing with locales " + locales + "; options " + + (options ? JSON.stringify(options) : options) + ".)"; + throw e; + } + }); +}); + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_CS_a.js b/js/src/tests/test402/ch10/10.3/10.3.2_CS_a.js new file mode 100644 index 000000000000..a946245b403a --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_CS_a.js @@ -0,0 +1,68 @@ +// Copyright 2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the function returned by Intl.Collator.prototype.compare + * returns 0 when comparing Strings that are considered canonically equivalent + * by the Unicode standard. + * @author Norbert Lindenberg + */ + +var collator = new Intl.Collator(); +var pairs = [ + // example from Unicode 5.0, section 3.7, definition D70 + ["o\u0308", "ö"], + // examples from Unicode 5.0, chapter 3.11 + ["ä\u0323", "a\u0323\u0308"], + ["a\u0308\u0323", "a\u0323\u0308"], + ["ạ\u0308", "a\u0323\u0308"], + ["ä\u0306", "a\u0308\u0306"], + ["ă\u0308", "a\u0306\u0308"], + // example from Unicode 5.0, chapter 3.12 + ["\u1111\u1171\u11B6", "퓛"], + // examples from UTS 10, Unicode Collation Algorithm + ["Å", "Å"], + ["Å", "A\u030A"], + ["x\u031B\u0323", "x\u0323\u031B"], + ["ự", "ụ\u031B"], + ["ự", "u\u031B\u0323"], + ["ự", "ư\u0323"], + ["ự", "u\u0323\u031B"], + // examples from UAX 15, Unicode Normalization Forms + ["Ç", "C\u0327"], + ["q\u0307\u0323", "q\u0323\u0307"], + ["가", "\u1100\u1161"], + ["Å", "A\u030A"], + ["Ω", "Ω"], + ["Å", "A\u030A"], + ["ô", "o\u0302"], + ["ṩ", "s\u0323\u0307"], + ["ḋ\u0323", "d\u0323\u0307"], + ["ḋ\u0323", "ḍ\u0307"], + ["q\u0307\u0323", "q\u0323\u0307"], + // examples involving supplementary characters from UCD NormalizationTest.txt + ["\uD834\uDD5E", "\uD834\uDD57\uD834\uDD65"], + ["\uD87E\uDC2B", "北"] + +]; +var i; +for (i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + if (collator.compare(pair[0], pair[1]) !== 0) { + $ERROR("Collator.compare considers " + pair[0] + " (" + toU(pair[0]) + + ") ≠ " + pair[1] + " (" + toU(pair[1]) + ")."); + } +} + +function toU(s) { + var result = ""; + var escape = "\\u0000"; + var i; + for (i = 0; i < s.length; i++) { + var hex = s.charCodeAt(i).toString(16); + result += escape.substring(0, escape.length - hex.length) + hex; + } + return result; +} + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_CS_b_NN.js b/js/src/tests/test402/ch10/10.3/10.3.2_CS_b_NN.js new file mode 100644 index 000000000000..c417d2b8a3c1 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_CS_b_NN.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the compare function isn't entirely unreasonable. + * This test is not normative. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// this test should be valid at least for the following locales +var locales = ["de", "en", "es", "fr", "it"]; +locales = Intl.Collator.supportedLocalesOf(locales, {localeMatcher: "lookup"}); +locales.forEach(function (locale) { + var collator = new Intl.Collator([locale], {sensitivity: "variant", localeMatcher: "lookup"}); + var a = ["L", "X", "C", "k", "Z", "H", "d", "m", "w", "A", "i", "f", "y", "E", "N", "V", "g", "J", "b"]; + a.sort(collator.compare); + var expected = ["A", "b", "C", "d", "E", "f", "g", "H", "i", "J", "k", "L", "m", "N", "V", "w", "X", "y", "Z"]; + testArraysAreSame(expected, a); +}); + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_CS_c_NN.js b/js/src/tests/test402/ch10/10.3/10.3.2_CS_c_NN.js new file mode 100644 index 000000000000..5d5060be5acd --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_CS_c_NN.js @@ -0,0 +1,22 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the compare function supports phonebook sorting if it says it does. + * This test is not normative. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// this test should be valid at least for the following locales +var locales = ["de-DE-u-co-phonebk", "de-u-co-phonebk"]; +var collator = new Intl.Collator(locales, {localeMatcher: "lookup"}); +if (locales.indexOf(collator.resolvedOptions().locale) !== -1) { + var a = ["A", "b", "Af", "Ab", "od", "off", "Ä", "ö"]; + a.sort(collator.compare); + var expected = ["A", "Ab", "Ä", "Af", "b", "od", "ö", "off"]; + testArraysAreSame(expected, a); +} + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_CS_d_NN.js b/js/src/tests/test402/ch10/10.3/10.3.2_CS_d_NN.js new file mode 100644 index 000000000000..be5f1aa338df --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_CS_d_NN.js @@ -0,0 +1,34 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the compare function supports different sensitivity settings. + * This test is not normative. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// this test should be valid at least for the following locales +var locales = ["de", "en", "es", "it"]; +locales = Intl.Collator.supportedLocalesOf(locales, {localeMatcher: "lookup"}); +locales.forEach(function (locale) { + var target = "Aa"; + var input = ["Aa", "bA", "E", "b", "aA", "fC", "áÁ", "Aã"]; + var expected = { + "base": ["Aa", "aA", "áÁ", "Aã"], + "accent": ["Aa", "aA"], + "case": ["Aa", "Aã"], + "variant": ["Aa"] + }; + Object.getOwnPropertyNames(expected).forEach(function (sensitivity) { + var collator = new Intl.Collator([locale], {usage: "search", + sensitivity: sensitivity, localeMatcher: "lookup"}); + var matches = input.filter(function (v) { + return collator.compare(v, target) === 0; + }); + testArraysAreSame(expected[sensitivity], matches); + }); +}); + diff --git a/js/src/tests/test402/ch10/10.3/10.3.2_L15.js b/js/src/tests/test402/ch10/10.3/10.3.2_L15.js new file mode 100644 index 000000000000..5845ea3ca177 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the getter for Intl.Collator.prototype.compare + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Object.getOwnPropertyDescriptor(Intl.Collator.prototype, "compare").get , true, false, [], 0); + diff --git a/js/src/tests/test402/ch10/10.3/10.3.3.js b/js/src/tests/test402/ch10/10.3/10.3.3.js new file mode 100644 index 000000000000..bc6b4fabb976 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.3.js @@ -0,0 +1,47 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the object returned by Intl.Collator.prototype.resolvedOptions + * has the right properties. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var actual = new Intl.Collator().resolvedOptions(); + +var actual2 = new Intl.Collator().resolvedOptions(); +if (actual2 === actual) { + $ERROR("resolvedOptions returned the same object twice."); +} + +// source: CLDR file common/bcp47/collation.xml; version CLDR 21. +var collations = [ + "default", // added + "big5han", + "dict", + "direct", + "ducet", + "gb2312", + "phonebk", + "phonetic", + "pinyin", + "reformed", + // "search", // excluded + "searchjl", + // "standard", // excluded + "stroke", + "trad", + "unihan" +]; + +// this assumes the default values where the specification provides them +mustHaveProperty(actual, "locale", isCanonicalizedStructurallyValidLanguageTag); +mustHaveProperty(actual, "usage", ["sort"]); +mustHaveProperty(actual, "sensitivity", ["variant"]); +mustHaveProperty(actual, "ignorePunctuation", [false]); +mustHaveProperty(actual, "collation", collations); +mayHaveProperty(actual, "numeric", [true, false]); +mayHaveProperty(actual, "caseFirst", ["upper", "lower", "false"]); + diff --git a/js/src/tests/test402/ch10/10.3/10.3.3_L15.js b/js/src/tests/test402/ch10/10.3/10.3.3_L15.js new file mode 100644 index 000000000000..718cc9fea6f5 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.prototype.resolvedOptions + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.Collator.prototype.resolvedOptions, true, false, [], 0); + diff --git a/js/src/tests/test402/ch10/10.3/10.3_L15.js b/js/src/tests/test402/ch10/10.3/10.3_L15.js new file mode 100644 index 000000000000..60719736c1e6 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.prototype + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.Collator.prototype, false, false, ["constructor", "compare", "resolvedOptions"]); + diff --git a/js/src/tests/test402/ch10/10.3/10.3_a.js b/js/src/tests/test402/ch10/10.3/10.3_a.js new file mode 100644 index 000000000000..aa2e52845967 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3_a.js @@ -0,0 +1,15 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.prototype is an object that + * has been initialized as an Intl.Collator. + */ + +// test by calling a function that would fail if "this" were not an object +// initialized as an Intl.Collator +if (Intl.Collator.prototype.compare("aаあ아", "aаあ아") !== 0) { + $ERROR("Intl.Collator.prototype is not an object that has been " + + "initialized as an Intl.Collator."); +} + diff --git a/js/src/tests/test402/ch10/10.3/10.3_b.js b/js/src/tests/test402/ch10/10.3/10.3_b.js new file mode 100644 index 000000000000..9c3c2db32e23 --- /dev/null +++ b/js/src/tests/test402/ch10/10.3/10.3_b.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator.prototype functions throw a + * TypeError if called on a non-object value or an object that hasn't been + * initialized as a Collator. + * @author Norbert Lindenberg + */ + +var functions = { + "compare getter": Object.getOwnPropertyDescriptor(Intl.Collator.prototype, "compare").get, + resolvedOptions: Intl.Collator.prototype.resolvedOptions +}; +var invalidTargets = [undefined, null, true, 0, "Collator", [], {}]; + +Object.getOwnPropertyNames(functions).forEach(function (functionName) { + var f = functions[functionName]; + invalidTargets.forEach(function (target) { + var error; + try { + f.call(target); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Calling " + functionName + " on " + target + " was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Calling " + functionName + " on " + target + " was rejected with wrong error " + error.name + "."); + } + }); +}); + diff --git a/js/src/tests/test402/ch10/10.3/browser.js b/js/src/tests/test402/ch10/10.3/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.3/shell.js b/js/src/tests/test402/ch10/10.3/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.4/10.4_a.js b/js/src/tests/test402/ch10/10.4/10.4_a.js new file mode 100644 index 000000000000..7527f65eb617 --- /dev/null +++ b/js/src/tests/test402/ch10/10.4/10.4_a.js @@ -0,0 +1,15 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.Collator instances have the specified properties. + * @author Norbert Lindenberg + */ + +var obj = new Intl.Collator(); + +var toStringValue = Object.prototype.toString.call(obj); +if (toStringValue !== "[object Object]") { + $ERROR("Intl.Collator instance produces wrong [[Class]] - toString returns " + toStringValue + "."); +} + diff --git a/js/src/tests/test402/ch10/10.4/browser.js b/js/src/tests/test402/ch10/10.4/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/10.4/shell.js b/js/src/tests/test402/ch10/10.4/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/browser.js b/js/src/tests/test402/ch10/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch10/shell.js b/js/src/tests/test402/ch10/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_1.js b/js/src/tests/test402/ch11/11.1/11.1.1_1.js new file mode 100644 index 000000000000..33af1697512d --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_1.js @@ -0,0 +1,43 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that an object can't be re-initialized as a NumberFormat. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var obj, error; + + // variant 1: use constructor in a "new" expression + obj = new Constructor(); + try { + Intl.NumberFormat.call(obj); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Re-initializing object created with \"new\" as NumberFormat was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Re-initializing object created with \"new\" as NumberFormat was rejected with wrong error " + error.name + "."); + } + + // variant 2: use constructor as a function + obj = Constructor.call({}); + error = undefined; + try { + Intl.NumberFormat.call(obj); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Re-initializing object created with constructor as function as NumberFormat was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Re-initializing object created with constructor as function as NumberFormat was rejected with wrong error " + error.name + "."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_15.js b/js/src/tests/test402/ch11/11.1/11.1.1_15.js new file mode 100644 index 000000000000..4d0467428c17 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_15.js @@ -0,0 +1,13 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option style is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.NumberFormat, "style", "string", ["decimal", "percent", "currency"], "decimal", + {extra: {"currency": {currency: "CNY"}}}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_17.js b/js/src/tests/test402/ch11/11.1/11.1.1_17.js new file mode 100644 index 000000000000..08c0e8e5c510 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_17.js @@ -0,0 +1,81 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option currency is processed correctly. + * @author Norbert Lindenberg + */ + +var validValues = ["CNY", "USD", "EUR", "IDR", "jpy", {toString: function () {return "INR";}}]; +var invalidValues = ["$", "SFr.", "US$", "ßP", {toString: function () {return;}}]; + +var defaultLocale = new Intl.NumberFormat().resolvedOptions().locale; + +validValues.forEach(function (value) { + var format, actual, expected; + + // with currency style, we should get the upper case form back + format = new Intl.NumberFormat([defaultLocale], {style: "currency", currency: value}); + actual = format.resolvedOptions().currency; + expected = value.toString().toUpperCase(); + if (actual !== expected) { + $ERROR("Incorrect resolved currency with currency style - expected " + + expected + "; got " + actual + "."); + } + + // without currency style, we shouldn't get any currency back + format = new Intl.NumberFormat([defaultLocale], {currency: value}); + actual = format.resolvedOptions().currency; + expected = undefined; + if (actual !== expected) { + $ERROR("Incorrect resolved currency with non-currency style - expected " + + expected + "; got " + actual + "."); + } + + // currencies specified through the locale must be ignored + format = new Intl.NumberFormat([defaultLocale + "-u-cu-krw"], {style: "currency", currency: value}); + actual = format.resolvedOptions().currency; + expected = value.toString().toUpperCase(); + if (actual !== expected) { + $ERROR("Incorrect resolved currency with -u-cu- and currency style - expected " + + expected + "; got " + actual + "."); + } + + format = new Intl.NumberFormat([defaultLocale + "-u-cu-krw"], {currency: value}); + actual = format.resolvedOptions().currency; + expected = undefined; + if (actual !== expected) { + $ERROR("Incorrect resolved currency with -u-cu- and non-currency style - expected " + + expected + "; got " + actual + "."); + } +}); + +invalidValues.forEach(function (value) { + function expectError(f) { + var error; + try { + f(); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid currency value " + value + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid currency value " + value + " was rejected with wrong error " + error.name + "."); + } + } + + expectError(function () { + return new Intl.NumberFormat([defaultLocale], {style: "currency", currency: value}); + }); + expectError(function () { + return new Intl.NumberFormat([defaultLocale], {currency: value}); + }); + expectError(function () { + return new Intl.NumberFormat([defaultLocale + "-u-cu-krw"], {style: "currency", currency: value}); + }); + expectError(function () { + return new Intl.NumberFormat([defaultLocale + "-u-cu-krw"], {currency: value}); + }); +}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_19.js b/js/src/tests/test402/ch11/11.1/11.1.1_19.js new file mode 100644 index 000000000000..e41ca5bec9bf --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_19.js @@ -0,0 +1,31 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the currency style can not be used without a specified currency. + * @author Norbert Lindenberg + */ + +var defaultLocale = new Intl.NumberFormat().resolvedOptions().locale; + +function expectError(f) { + var error; + try { + f(); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid currency value " + value + " was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Invalid currency value " + value + " was rejected with wrong error " + error.name + "."); + } +} + +expectError(function () { + return new Intl.NumberFormat([defaultLocale], {style: "currency"}); +}); +expectError(function () { + return new Intl.NumberFormat([defaultLocale + "-u-cu-krw"], {style: "currency"}); +}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_20_c.js b/js/src/tests/test402/ch11/11.1/11.1.1_20_c.js new file mode 100644 index 000000000000..20b7910b02ee --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_20_c.js @@ -0,0 +1,196 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the number of fractional digits is determined correctly for currencies. + * @author Norbert Lindenberg + */ + +// data from http://www.currency-iso.org/dl_iso_table_a1.xml, 2013-02-25 +var currencyDigits = { + AED: 2, + AFN: 2, + ALL: 2, + AMD: 2, + ANG: 2, + AOA: 2, + ARS: 2, + AUD: 2, + AWG: 2, + AZN: 2, + BAM: 2, + BBD: 2, + BDT: 2, + BGN: 2, + BHD: 3, + BIF: 0, + BMD: 2, + BND: 2, + BOB: 2, + BOV: 2, + BRL: 2, + BSD: 2, + BTN: 2, + BWP: 2, + BYR: 0, + BZD: 2, + CAD: 2, + CDF: 2, + CHE: 2, + CHF: 2, + CHW: 2, + CLF: 0, + CLP: 0, + CNY: 2, + COP: 2, + COU: 2, + CRC: 2, + CUC: 2, + CUP: 2, + CVE: 2, + CZK: 2, + DJF: 0, + DKK: 2, + DOP: 2, + DZD: 2, + EGP: 2, + ERN: 2, + ETB: 2, + EUR: 2, + FJD: 2, + FKP: 2, + GBP: 2, + GEL: 2, + GHS: 2, + GIP: 2, + GMD: 2, + GNF: 0, + GTQ: 2, + GYD: 2, + HKD: 2, + HNL: 2, + HRK: 2, + HTG: 2, + HUF: 2, + IDR: 2, + ILS: 2, + INR: 2, + IQD: 3, + IRR: 2, + ISK: 0, + JMD: 2, + JOD: 3, + JPY: 0, + KES: 2, + KGS: 2, + KHR: 2, + KMF: 0, + KPW: 2, + KRW: 0, + KWD: 3, + KYD: 2, + KZT: 2, + LAK: 2, + LBP: 2, + LKR: 2, + LRD: 2, + LSL: 2, + LTL: 2, + LVL: 2, + LYD: 3, + MAD: 2, + MDL: 2, + MGA: 2, + MKD: 2, + MMK: 2, + MNT: 2, + MOP: 2, + MRO: 2, + MUR: 2, + MVR: 2, + MWK: 2, + MXN: 2, + MXV: 2, + MYR: 2, + MZN: 2, + NAD: 2, + NGN: 2, + NIO: 2, + NOK: 2, + NPR: 2, + NZD: 2, + OMR: 3, + PAB: 2, + PEN: 2, + PGK: 2, + PHP: 2, + PKR: 2, + PLN: 2, + PYG: 0, + QAR: 2, + RON: 2, + RSD: 2, + RUB: 2, + RWF: 0, + SAR: 2, + SBD: 2, + SCR: 2, + SDG: 2, + SEK: 2, + SGD: 2, + SHP: 2, + SLL: 2, + SOS: 2, + SRD: 2, + SSP: 2, + STD: 2, + SVC: 2, + SYP: 2, + SZL: 2, + THB: 2, + TJS: 2, + TMT: 2, + TND: 3, + TOP: 2, + TRY: 2, + TTD: 2, + TWD: 2, + TZS: 2, + UAH: 2, +// UGX: 2, will be changed to 0 when maintenance agency releases updated table + USD: 2, + USN: 2, + USS: 2, + UYI: 0, + UYU: 2, + UZS: 2, + VEF: 2, + VND: 0, + VUV: 0, + WST: 2, + XAF: 0, + XCD: 2, + XOF: 0, + XPF: 0, + YER: 2, + ZAR: 2, + ZMW: 2, + ZWL: 2 +}; + +Object.getOwnPropertyNames(currencyDigits).forEach(function (currency) { + var digits = currencyDigits[currency]; + format = Intl.NumberFormat([], {style: "currency", currency: currency}); + var min = format.resolvedOptions().minimumFractionDigits; + var max = format.resolvedOptions().maximumFractionDigits; + if (min !== digits) { + $ERROR("Didn't get correct minimumFractionDigits for currency " + + currency + "; expected " + digits + ", got " + min + "."); + } + if (max !== digits) { + $ERROR("Didn't get correct maximumFractionDigits for currency " + + currency + "; expected " + digits + ", got " + max + "."); + } +}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_21.js b/js/src/tests/test402/ch11/11.1/11.1.1_21.js new file mode 100644 index 000000000000..1751b8b5745f --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_21.js @@ -0,0 +1,15 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option currencyDisplay is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.NumberFormat, "currencyDisplay", "string", ["code", "symbol", "name"], + "symbol", {extra: {any: {style: "currency", currency: "XDR"}}}); +testOption(Intl.NumberFormat, "currencyDisplay", "string", ["code", "symbol", "name"], + undefined, {noReturn: true}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_32.js b/js/src/tests/test402/ch11/11.1/11.1.1_32.js new file mode 100644 index 000000000000..9196318efbf2 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_32.js @@ -0,0 +1,44 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the options minimumSignificantDigits and + * maximumSignificantDigits are read in the right sequence. + * @author Norbert Lindenberg + */ + +var read = 0; + +function readMinimumSignificantDigits() { + ++read; + if (read === 1) { + return 0; // invalid value, but on first read that's OK + } else if (read === 3) { + return 1; // valid value + } else { + $ERROR("minimumSignificantDigits read out of sequence: " + read + "."); + } +} + +function readMaximumSignificantDigits() { + ++read; + if (read === 2) { + return 0; // invalid value, but on first read that's OK + } else if (read === 4) { + return 1; // valid value + } else { + $ERROR("maximumSignificantDigits read out of sequence: " + read + "."); + } +} + +var options = {}; +Object.defineProperty(options, "minimumSignificantDigits", + { get: readMinimumSignificantDigits }); +Object.defineProperty(options, "maximumSignificantDigits", + { get: readMaximumSignificantDigits }); + +new Intl.NumberFormat("de", options); + +if (read !== 4) { + $ERROR("insuffient number of property reads: " + read + "."); +} diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_34.js b/js/src/tests/test402/ch11/11.1/11.1.1_34.js new file mode 100644 index 000000000000..98ba9a06207a --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_34.js @@ -0,0 +1,12 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option useGrouping is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.NumberFormat, "useGrouping", "boolean", undefined, true); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_6.js b/js/src/tests/test402/ch11/11.1/11.1.1_6.js new file mode 100644 index 000000000000..5b9d342ebf75 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_6.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["localeMatcher"]); + +var locale = new Intl.NumberFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +if (!isCanonicalizedStructurallyValidLanguageTag(locale)) { + $ERROR("NumberFormat returns invalid locale " + locale + "."); +} + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_7.js b/js/src/tests/test402/ch11/11.1/11.1.1_7.js new file mode 100644 index 000000000000..4b13b245b74c --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_7.js @@ -0,0 +1,12 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option localeMatcher is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.NumberFormat, "localeMatcher", "string", ["lookup", "best fit"], "best fit", {noReturn: true}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.1_a.js b/js/src/tests/test402/ch11/11.1/11.1.1_a.js new file mode 100644 index 000000000000..611816b61c16 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.1_a.js @@ -0,0 +1,18 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that constructing a NumberFormat doesn't create or modify + * unwanted properties on the RegExp constructor. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testForUnwantedRegExpChanges(function () { + new Intl.NumberFormat("de-DE-u-nu-latn"); +}); + +testForUnwantedRegExpChanges(function () { + new Intl.NumberFormat("de-DE-u-nu-latn", {style: "currency", currency: "EUR"}); +}); diff --git a/js/src/tests/test402/ch11/11.1/11.1.2.1_4.js b/js/src/tests/test402/ch11/11.1/11.1.2.1_4.js new file mode 100644 index 000000000000..18b5b98faf34 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.2.1_4.js @@ -0,0 +1,21 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that for non-object values passed as this to NumberFormat a + * wrapper object will be initialized and returned. + * @author Norbert Lindenberg + */ + +var thisValues = [true, 42, "国際化"]; + +thisValues.forEach(function (value) { + var format = Intl.NumberFormat.call(value); + // check that the returned object functions as a number format + var referenceFormat = new Intl.NumberFormat(); + if (Intl.NumberFormat.prototype.format.call(format, 12.3456) !== referenceFormat.format(12.3456)) { + $ERROR("NumberFormat initialized from " + value + " doesn't behave like normal number format."); + } + return true; +}); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.2.js b/js/src/tests/test402/ch11/11.1/11.1.2.js new file mode 100644 index 000000000000..0ca8cbbdaef0 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.2.js @@ -0,0 +1,30 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat can be subclassed. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// get a number format and have it format an array of numbers for comparison with the subclass +var locales = ["tlh", "id", "en"]; +var a = [0, 1, -1, -123456.789, -Infinity, NaN]; +var referenceNumberFormat = new Intl.NumberFormat(locales); +var referenceFormatted = a.map(referenceNumberFormat.format); + +function MyNumberFormat(locales, options) { + Intl.NumberFormat.call(this, locales, options); + // could initialize MyNumberFormat properties +} + +MyNumberFormat.prototype = Object.create(Intl.NumberFormat.prototype); +MyNumberFormat.prototype.constructor = MyNumberFormat; +// could add methods to MyNumberFormat.prototype + +var format = new MyNumberFormat(locales); +var actual = a.map(format.format); +testArraysAreSame(referenceFormatted, actual); + diff --git a/js/src/tests/test402/ch11/11.1/11.1.3.js b/js/src/tests/test402/ch11/11.1/11.1.3.js new file mode 100644 index 000000000000..f0bfb5552d8b --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1.3.js @@ -0,0 +1,19 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that objects constructed by Intl.NumberFormat have the specified internal properties. + * @author Norbert Lindenberg + */ + +var obj = new Intl.NumberFormat(); + +var actualPrototype = Object.getPrototypeOf(obj); +if (actualPrototype !== Intl.NumberFormat.prototype) { + $ERROR("Prototype of object constructed by Intl.NumberFormat isn't Intl.NumberFormat.prototype; got " + actualPrototype); +} + +if (!Object.isExtensible(obj)) { + $ERROR("Object constructed by Intl.NumberFormat must be extensible."); +} + diff --git a/js/src/tests/test402/ch11/11.1/11.1_L15.js b/js/src/tests/test402/ch11/11.1/11.1_L15.js new file mode 100644 index 000000000000..e40ffc53e195 --- /dev/null +++ b/js/src/tests/test402/ch11/11.1/11.1_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.NumberFormat, true, true, ["supportedLocalesOf"], 0); + diff --git a/js/src/tests/test402/ch11/11.1/browser.js b/js/src/tests/test402/ch11/11.1/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.1/shell.js b/js/src/tests/test402/ch11/11.1/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.2/11.2.1.js b/js/src/tests/test402/ch11/11.2/11.2.1.js new file mode 100644 index 000000000000..83bebb283575 --- /dev/null +++ b/js/src/tests/test402/ch11/11.2/11.2.1.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype has the required attributes. + * @author Norbert Lindenberg + */ + +var desc = Object.getOwnPropertyDescriptor(Intl.NumberFormat, "prototype"); +if (desc === undefined) { + $ERROR("Intl.NumberFormat.prototype is not defined."); +} +if (desc.writable) { + $ERROR("Intl.NumberFormat.prototype must not be writable."); +} +if (desc.enumerable) { + $ERROR("Intl.NumberFormat.prototype must not be enumerable."); +} +if (desc.configurable) { + $ERROR("Intl.NumberFormat.prototype must not be configurable."); +} + diff --git a/js/src/tests/test402/ch11/11.2/11.2.2_L15.js b/js/src/tests/test402/ch11/11.2/11.2.2_L15.js new file mode 100644 index 000000000000..49dce3bae91a --- /dev/null +++ b/js/src/tests/test402/ch11/11.2/11.2.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.supportedLocalesOf + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.NumberFormat.supportedLocalesOf, true, false, [], 1); + diff --git a/js/src/tests/test402/ch11/11.2/11.2.2_a.js b/js/src/tests/test402/ch11/11.2/11.2.2_a.js new file mode 100644 index 000000000000..c6c9f9a46dc6 --- /dev/null +++ b/js/src/tests/test402/ch11/11.2/11.2.2_a.js @@ -0,0 +1,28 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat has a supportedLocalesOf + * property, and it works as planned. + * @author: Roozbeh Pournader + */ + +var defaultLocale = new Intl.NumberFormat().resolvedOptions().locale; +var notSupported = 'zxx'; // "no linguistic content" +var requestedLocales = [defaultLocale, notSupported]; + +var supportedLocales; + +if (!Intl.NumberFormat.hasOwnProperty('supportedLocalesOf')) { + $ERROR("Intl.NumberFormat doesn't have a supportedLocalesOf property."); +} + +supportedLocales = Intl.NumberFormat.supportedLocalesOf(requestedLocales); +if (supportedLocales.length !== 1) { + $ERROR('The length of supported locales list is not 1.'); +} + +if (supportedLocales[0] !== defaultLocale) { + $ERROR('The default locale is not returned in the supported list.'); +} + diff --git a/js/src/tests/test402/ch11/11.2/11.2.2_b.js b/js/src/tests/test402/ch11/11.2/11.2.2_b.js new file mode 100644 index 000000000000..6b4d77e7737a --- /dev/null +++ b/js/src/tests/test402/ch11/11.2/11.2.2_b.js @@ -0,0 +1,13 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.supportedLocalesOf + * doesn't access arguments that it's not given. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintDataProperty(Object.prototype, "1"); +new Intl.NumberFormat("und"); diff --git a/js/src/tests/test402/ch11/11.2/11.2.3_b.js b/js/src/tests/test402/ch11/11.2/11.2.3_b.js new file mode 100644 index 000000000000..70fe7cf119a2 --- /dev/null +++ b/js/src/tests/test402/ch11/11.2/11.2.3_b.js @@ -0,0 +1,46 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat does not accept Unicode locale + * extension keys and values that are not allowed. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var locales = ["ja-JP", "zh-Hans-CN", "zh-Hant-TW"]; +var input = 1234567.89; + +locales.forEach(function (locale) { + var defaultNumberFormat = new Intl.NumberFormat([locale]); + var defaultOptions = defaultNumberFormat.resolvedOptions(); + var defaultOptionsJSON = JSON.stringify(defaultOptions); + var defaultLocale = defaultOptions.locale; + var defaultFormatted = defaultNumberFormat.format(input); + + var keyValues = { + "cu": ["USD", "EUR", "JPY", "CNY", "TWD", "invalid"], + "nu": ["native", "traditio", "finance", "invalid"] + }; + + Object.getOwnPropertyNames(keyValues).forEach(function (key) { + keyValues[key].forEach(function (value) { + var numberFormat = new Intl.NumberFormat([locale + "-u-" + key + "-" + value]); + var options = numberFormat.resolvedOptions(); + if (options.locale !== defaultLocale) { + $ERROR("Locale " + options.locale + " is affected by key " + + key + "; value " + value + "."); + } + if (JSON.stringify(options) !== defaultOptionsJSON) { + $ERROR("Resolved options " + JSON.stringify(options) + " are affected by key " + + key + "; value " + value + "."); + } + if (defaultFormatted !== numberFormat.format(input)) { + $ERROR("Formatted value " + numberFormat.format(input) + " is affected by key " + + key + "; value " + value + "."); + } + }); + }); +}); + diff --git a/js/src/tests/test402/ch11/11.2/browser.js b/js/src/tests/test402/ch11/11.2/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.2/shell.js b/js/src/tests/test402/ch11/11.2/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.3/11.3.1.js b/js/src/tests/test402/ch11/11.3/11.3.1.js new file mode 100644 index 000000000000..46c7fc519388 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.1.js @@ -0,0 +1,14 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.constructor is the + * Intl.NumberFormat. + * @author: Roozbeh Pournader + */ + +if (Intl.NumberFormat.prototype.constructor !== Intl.NumberFormat) { + $ERROR("Intl.NumberFormat.prototype.constructor is not the same as " + + "Intl.NumberFormat"); +} + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_1_a_L15.js b/js/src/tests/test402/ch11/11.3/11.3.2_1_a_L15.js new file mode 100644 index 000000000000..8e1c9583505c --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_1_a_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the function returned by Intl.NumberFormat.prototype.format + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(new Intl.NumberFormat().format, true, false, [], 1); + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_1_a_ii.js b/js/src/tests/test402/ch11/11.3/11.3.2_1_a_ii.js new file mode 100644 index 000000000000..cb284f43ef05 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_1_a_ii.js @@ -0,0 +1,27 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.format + * converts other types to numbers. + * @author: Roozbeh Pournader + */ + +var formatter = new Intl.NumberFormat(); +var testData = [undefined, null, true, '0.6666666', {valueOf: function () { return '0.1234567';}}]; +var number; +var i, input, correctResult, result; + +for (i in testData) { + input = testData[i]; + number = +input; + correctResult = formatter.format(number); + + result = formatter.format(input); + if (result !== correctResult) { + $ERROR('Intl.NumberFormat does not convert other ' + + 'types to numbers. Input: "'+input+'" Output: "'+result+'" '+ + 'Expected output: "'+correctResult+'"'); + } +} + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_1_c.js b/js/src/tests/test402/ch11/11.3/11.3.2_1_c.js new file mode 100644 index 000000000000..3fc877b310b5 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_1_c.js @@ -0,0 +1,41 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that format function is bound to its Intl.NumberFormat. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var numbers = [0, -0, 1, -1, 5.5, 123, -123, -123.45, 123.44501, 0.001234, + -0.00000000123, 0.00000000000000000000000000000123, 1.2, 0.0000000012344501, + 123445.01, 12344501000000000000000000000000000, -12344501000000000000000000000000000, + Infinity, -Infinity, NaN]; +var locales = [undefined, ["de"], ["th-u-nu-thai"], ["en"], ["ja-u-nu-jpanfin"], ["ar-u-nu-arab"]]; +var options = [ + undefined, + {style: "percent"}, + {style: "currency", currency: "EUR", currencyDisplay: "symbol"}, + {style: "currency", currency: "IQD", currencyDisplay: "symbol"}, + {style: "currency", currency: "KMF", currencyDisplay: "symbol"}, + {style: "currency", currency: "CLF", currencyDisplay: "symbol"}, + {useGrouping: false, minimumIntegerDigits: 3, minimumFractionDigits: 1, maximumFractionDigits: 3} +]; + +locales.forEach(function (locales) { + options.forEach(function (options) { + var formatObj = new Intl.NumberFormat(locales, options); + var formatFunc = formatObj.format; + numbers.forEach(function (number) { + var referenceFormatted = formatObj.format(number); + var formatted = formatFunc(number); + if (referenceFormatted !== formatted) { + $ERROR("format function produces different result than format method for locales " + + locales + "; options: " + (options ? JSON.stringify(options) : options) + + " : " + formatted + " vs. " + referenceFormatted + "."); + } + }); + }); +}); + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_FN_1.js b/js/src/tests/test402/ch11/11.3/11.3.2_FN_1.js new file mode 100644 index 000000000000..5f14e7772d03 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_FN_1.js @@ -0,0 +1,19 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.format + * doesn't treat all numbers as negative. + * @author: Roozbeh Pournader + */ + +var formatter = new Intl.NumberFormat(); + +if (formatter.format(1) === formatter.format(-1)) { + $ERROR('Intl.NumberFormat is formatting 1 and -1 the same way.'); +} + +if (formatter.format(-0) !== formatter.format(0)) { + $ERROR('Intl.NumberFormat is formatting signed zeros differently.'); +} + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_FN_2.js b/js/src/tests/test402/ch11/11.3/11.3.2_FN_2.js new file mode 100644 index 000000000000..ec11a679d0e6 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_FN_2.js @@ -0,0 +1,59 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.format + * handles NaN, Infinity, and -Infinity properly. + * @author: Roozbeh Pournader + */ + +// FIXME: We are only listing Numeric_Type=Decimal. May need to add more +// when the spec clarifies. Current as of Unicode 6.1. +var hasUnicodeDigits = new RegExp('.*([' + + '0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F' + + '\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF' + + '\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9' + + '\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819' + + '\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59' + + '\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9' + + '\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19' + + ']|' + + '\uD801[\uDCA0-\uDCA9]|' + + '\uD804[\uDC66-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9]|' + + '\uD805[\uDEC0-\uDEC9]|' + + '\uD835[\uDFCE-\uDFFF])'); + +var formatter = new Intl.NumberFormat(); +var formattedNaN = formatter.format(NaN); +var formattedInfinity = formatter.format(Infinity); +var formattedNegativeInfinity = formatter.format(-Infinity); + +if (formattedNaN === formattedInfinity) { + $ERROR('Intl.NumberFormat formats NaN and Infinity the ' + + 'same way.'); +} + +if (formattedNaN === formattedNegativeInfinity) { + $ERROR('Intl.NumberFormat formats NaN and negative ' + + 'Infinity the same way.'); +} + +if (formattedInfinity === formattedNegativeInfinity) { + $ERROR('Intl.NumberFormat formats Infinity and ' + + 'negative Infinity the same way.'); +} + +if (hasUnicodeDigits.test(formattedNaN)) { + $ERROR('Intl.NumberFormat formats NaN using a digit.'); +} + +if (hasUnicodeDigits.test(formattedInfinity)) { + $ERROR('Intl.NumberFormat formats Infinity using a ' + + 'digit.'); +} + +if (hasUnicodeDigits.test(formattedNegativeInfinity)) { + $ERROR('Intl.NumberFormat formats negative Infinity ' + + 'using a digit.'); +} + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_FN_3_b.js b/js/src/tests/test402/ch11/11.3/11.3.2_FN_3_b.js new file mode 100644 index 000000000000..efe15575d9aa --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_FN_3_b.js @@ -0,0 +1,27 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.format + * formats percent values properly. + * @author: Roozbeh Pournader + */ + +var numberFormatter = new Intl.NumberFormat(); +var percentFormatter = new Intl.NumberFormat(undefined, {style: 'percent'}); + +var formattedTwenty = numberFormatter.format(20); +var formattedTwentyPercent = percentFormatter.format(0.20); + +// FIXME: May not work for some theoretical locales where percents and +// normal numbers are formatted using different numbering systems. +if (formattedTwentyPercent.indexOf(formattedTwenty) === -1) { + $ERROR("Intl.NumberFormat's formatting of 20% does not include a " + + "formatting of 20 as a substring."); +} + +// FIXME: Move this to somewhere appropriate +if (percentFormatter.format(0.011) === percentFormatter.format(0.02)) { + $ERROR('Intl.NumberFormat is formatting 1.1% and 2% the same way.'); +} + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_FN_3_e.js b/js/src/tests/test402/ch11/11.3/11.3.2_FN_3_e.js new file mode 100644 index 000000000000..234ae63254cf --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_FN_3_e.js @@ -0,0 +1,47 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.format + * supports all alternative numbering systems. + * @author: Roozbeh Pournader + */ + +var numberingSystems = { + arab: 0x0660, + arabext: 0x06F0, + beng: 0x09E6, + deva: 0x0966, + fullwide: 0xFF10, + gujr: 0x0AE6, + guru: 0x0A66, + hanidec: [0x3007, 0x4E00, 0x4E8C, 0x4E09, 0x56DB, + 0x4E94, 0x516D, 0x4E03, 0x516B, 0x4E5D], + khmr: 0x17E0, + knda: 0x0CE6, + laoo: 0x0ED0, + latn: 0x0030, + mlym: 0x0D66, + mong: 0x1810, + mymr: 0x1040, + orya: 0x0B66, + tamldec: 0x0BE6, + telu: 0x0C66, + thai: 0x0E50, + tibt: 0x0F20 +}; + +var options, formatter; +var s, zeroCode, digitList; + +for (s in numberingSystems) { + zeroCode = numberingSystems[s]; + if (typeof zeroCode === 'number') { + digitList = [zeroCode, zeroCode+1, zeroCode+2, zeroCode+3, zeroCode+4, + zeroCode+5, zeroCode+6, zeroCode+7, zeroCode+8, zeroCode+9]; + numberingSystems[s] = digitList; + } +} + +// FIXME: Unfinished + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_L15.js b/js/src/tests/test402/ch11/11.3/11.3.2_L15.js new file mode 100644 index 000000000000..17b688b7a9d1 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the getter for Intl.NumberFormat.prototype.format + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, "format").get , true, false, [], 0); + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_TRF.js b/js/src/tests/test402/ch11/11.3/11.3.2_TRF.js new file mode 100644 index 000000000000..32ee5cd9aab4 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_TRF.js @@ -0,0 +1,52 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the digits are determined correctly when specifying pre/post decimal digits. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var locales = [ + new Intl.NumberFormat().resolvedOptions().locale, + "ar", "de", "th", "ja" +]; +var numberingSystems = [ + "arab", + "latn", + "thai", + "hanidec" +]; +var testData = { + "0": "000.0", + "-0": "000.0", + "123": "123.0", + "-123": "-123.0", + "12345": "12345.0", + "-12345": "-12345.0", + "123.45": "123.45", + "-123.45": "-123.45", + "123.44501": "123.445", + "-123.44501": "-123.445", + "0.001234": "000.001", + "-0.001234": "-000.001", + "0.00000000123": "000.0", + "-0.00000000123": "-000.0", + "0.00000000000000000000000000000123": "000.0", + "-0.00000000000000000000000000000123": "-000.0", + "1.2": "001.2", + "-1.2": "-001.2", + "0.0000000012344501": "000.0", + "-0.0000000012344501": "-000.0", + "123445.01": "123445.01", + "-123445.01": "-123445.01", + "12344501000000000000000000000000000": "12344501000000000000000000000000000.0", + "-12344501000000000000000000000000000": "-12344501000000000000000000000000000.0" +}; + +testNumberFormat(locales, numberingSystems, + {useGrouping: false, minimumIntegerDigits: 3, minimumFractionDigits: 1, maximumFractionDigits: 3}, + testData); + diff --git a/js/src/tests/test402/ch11/11.3/11.3.2_TRP.js b/js/src/tests/test402/ch11/11.3/11.3.2_TRP.js new file mode 100644 index 000000000000..9409e258d14b --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.2_TRP.js @@ -0,0 +1,52 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the digits are determined correctly when specifying significant digits. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var locales = [ + new Intl.NumberFormat().resolvedOptions().locale, + "ar", "de", "th", "ja" +]; +var numberingSystems = [ + "arab", + "latn", + "thai", + "hanidec" +]; +var testData = { + "0": "0.00", + "-0": "0.00", + "123": "123", + "-123": "-123", + "12345": "12345", + "-12345": "-12345", + "123.45": "123.45", + "-123.45": "-123.45", + "123.44501": "123.45", + "-123.44501": "-123.45", + "0.001234": "0.001234", + "-0.001234": "-0.001234", + "0.00000000123": "0.00000000123", + "-0.00000000123": "-0.00000000123", + "0.00000000000000000000000000000123": "0.00000000000000000000000000000123", + "-0.00000000000000000000000000000123": "-0.00000000000000000000000000000123", + "1.2": "1.20", + "-1.2": "-1.20", + "0.0000000012344501": "0.0000000012345", + "-0.0000000012344501": "-0.0000000012345", + "123445.01": "123450", + "-123445.01": "-123450", + "12344501000000000000000000000000000": "12345000000000000000000000000000000", + "-12344501000000000000000000000000000": "-12345000000000000000000000000000000" +}; + +testNumberFormat(locales, numberingSystems, + {useGrouping: false, minimumSignificantDigits: 3, maximumSignificantDigits: 5}, + testData); + diff --git a/js/src/tests/test402/ch11/11.3/11.3.3.js b/js/src/tests/test402/ch11/11.3/11.3.3.js new file mode 100644 index 000000000000..5a220ccc9b7a --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.3.js @@ -0,0 +1,31 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the object returned by Intl.NumberFormat.prototype.resolvedOptions + * has the right properties. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var actual = new Intl.NumberFormat().resolvedOptions(); + +var actual2 = new Intl.NumberFormat().resolvedOptions(); +if (actual2 === actual) { + $ERROR("resolvedOptions returned the same object twice."); +} + +// this assumes the default values where the specification provides them +mustHaveProperty(actual, "locale", isCanonicalizedStructurallyValidLanguageTag); +mustHaveProperty(actual, "numberingSystem", isValidNumberingSystem); +mustHaveProperty(actual, "style", ["decimal"]); +mustNotHaveProperty(actual, "currency"); +mustNotHaveProperty(actual, "currencyDisplay"); +mustHaveProperty(actual, "minimumIntegerDigits", [1]); +mustHaveProperty(actual, "minimumFractionDigits", [0]); +mustHaveProperty(actual, "maximumFractionDigits", [3]); +mustNotHaveProperty(actual, "minimumSignificantDigits"); +mustNotHaveProperty(actual, "maximumSignificantDigits"); +mustHaveProperty(actual, "useGrouping", [true]); + diff --git a/js/src/tests/test402/ch11/11.3/11.3.3_L15.js b/js/src/tests/test402/ch11/11.3/11.3.3_L15.js new file mode 100644 index 000000000000..b9f95866d1af --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype.resolvedOptions + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.NumberFormat.prototype.resolvedOptions, true, false, [], 0); + diff --git a/js/src/tests/test402/ch11/11.3/11.3_L15.js b/js/src/tests/test402/ch11/11.3/11.3_L15.js new file mode 100644 index 000000000000..ac1f0c05dfe8 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.NumberFormat.prototype, false, false, ["constructor", "format", "resolvedOptions"]); + diff --git a/js/src/tests/test402/ch11/11.3/11.3_a.js b/js/src/tests/test402/ch11/11.3/11.3_a.js new file mode 100644 index 000000000000..282a10bf6ee7 --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3_a.js @@ -0,0 +1,16 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype is an object that + * has been initialized as an Intl.NumberFormat. + * @author: Roozbeh Pournader + */ + +// test by calling a function that would fail if "this" were not an object +// initialized as an Intl.NumberFormat +if (typeof Intl.NumberFormat.prototype.format(0) !== "string") { + $ERROR("Intl.NumberFormat's prototype is not an object that has been " + + "initialized as an Intl.NumberFormat"); +} + diff --git a/js/src/tests/test402/ch11/11.3/11.3_b.js b/js/src/tests/test402/ch11/11.3/11.3_b.js new file mode 100644 index 000000000000..6d0162b1d91e --- /dev/null +++ b/js/src/tests/test402/ch11/11.3/11.3_b.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat.prototype functions throw a + * TypeError if called on a non-object value or an object that hasn't been + * initialized as a NumberFormat. + * @author Norbert Lindenberg + */ + +var functions = { + "format getter": Object.getOwnPropertyDescriptor(Intl.NumberFormat.prototype, "format").get, + resolvedOptions: Intl.NumberFormat.prototype.resolvedOptions +}; +var invalidTargets = [undefined, null, true, 0, "NumberFormat", [], {}]; + +Object.getOwnPropertyNames(functions).forEach(function (functionName) { + var f = functions[functionName]; + invalidTargets.forEach(function (target) { + var error; + try { + f.call(target); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Calling " + functionName + " on " + target + " was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Calling " + functionName + " on " + target + " was rejected with wrong error " + error.name + "."); + } + }); +}); + diff --git a/js/src/tests/test402/ch11/11.3/browser.js b/js/src/tests/test402/ch11/11.3/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.3/shell.js b/js/src/tests/test402/ch11/11.3/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.4/11.4_a.js b/js/src/tests/test402/ch11/11.4/11.4_a.js new file mode 100644 index 000000000000..a562879ece36 --- /dev/null +++ b/js/src/tests/test402/ch11/11.4/11.4_a.js @@ -0,0 +1,15 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.NumberFormat instances have the specified properties. + * @author Norbert Lindenberg + */ + +var obj = new Intl.NumberFormat(); + +var toStringValue = Object.prototype.toString.call(obj); +if (toStringValue !== "[object Object]") { + $ERROR("Intl.NumberFormat instance produces wrong [[Class]] - toString returns " + toStringValue + "."); +} + diff --git a/js/src/tests/test402/ch11/11.4/browser.js b/js/src/tests/test402/ch11/11.4/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/11.4/shell.js b/js/src/tests/test402/ch11/11.4/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/browser.js b/js/src/tests/test402/ch11/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch11/shell.js b/js/src/tests/test402/ch11/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_1.js b/js/src/tests/test402/ch12/12.1/12.1.1_1.js new file mode 100644 index 000000000000..8136fb421001 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_1.js @@ -0,0 +1,43 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that an object can't be re-initialized as a DateTimeFormat. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testWithIntlConstructors(function (Constructor) { + var obj, error; + + // variant 1: use constructor in a "new" expression + obj = new Constructor(); + try { + Intl.DateTimeFormat.call(obj); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Re-initializing object created with \"new\" as DateTimeFormat was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Re-initializing object created with \"new\" as DateTimeFormat was rejected with wrong error " + error.name + "."); + } + + // variant 2: use constructor as a function + obj = Constructor.call({}); + error = undefined; + try { + Intl.DateTimeFormat.call(obj); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Re-initializing object created with constructor as function as DateTimeFormat was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Re-initializing object created with constructor as function as DateTimeFormat was rejected with wrong error " + error.name + "."); + } + + return true; +}); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_18.js b/js/src/tests/test402/ch12/12.1/12.1.1_18.js new file mode 100644 index 000000000000..f75ea1e32749 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_18.js @@ -0,0 +1,15 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option hour12 is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.DateTimeFormat, "hour12", "boolean", undefined, undefined, + {extra: {any: {hour: "numeric", minute: "numeric"}}}); +testOption(Intl.DateTimeFormat, "hour12", "boolean", undefined, undefined, + {noReturn: true}); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_22.js b/js/src/tests/test402/ch12/12.1/12.1.1_22.js new file mode 100644 index 000000000000..5c317c6b9292 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_22.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZone"]); + +var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +if (!isCanonicalizedStructurallyValidLanguageTag(locale)) { + $ERROR("DateTimeFormat returns invalid locale " + locale + "."); +} + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_23.js b/js/src/tests/test402/ch12/12.1/12.1.1_23.js new file mode 100644 index 000000000000..d26e1d28c82e --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_23.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the options for the date and time components are processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +getDateTimeComponents().forEach(function (component) { + testOption(Intl.DateTimeFormat, component, "string", getDateTimeComponentValues(component), undefined, {isILD: true}); +}); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_25.js b/js/src/tests/test402/ch12/12.1/12.1.1_25.js new file mode 100644 index 000000000000..ccaf7be035e0 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_25.js @@ -0,0 +1,12 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option formatMatcher is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.DateTimeFormat, "formatMatcher", "string", ["basic", "best fit"], "best fit", {noReturn: true}); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_5.js b/js/src/tests/test402/ch12/12.1/12.1.1_5.js new file mode 100644 index 000000000000..c6b166814c6d --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_5.js @@ -0,0 +1,18 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["localeMatcher"]); + +var locale = new Intl.DateTimeFormat(undefined, {localeMatcher: "lookup"}).resolvedOptions().locale; +if (!isCanonicalizedStructurallyValidLanguageTag(locale)) { + $ERROR("DateTimeFormat returns invalid locale " + locale + "."); +} + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_6.js b/js/src/tests/test402/ch12/12.1/12.1.1_6.js new file mode 100644 index 000000000000..148ca02f6547 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_6.js @@ -0,0 +1,12 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the option localeMatcher is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testOption(Intl.DateTimeFormat, "localeMatcher", "string", ["lookup", "best fit"], "best fit", {noReturn: true}); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_TDTO.js b/js/src/tests/test402/ch12/12.1/12.1.1_TDTO.js new file mode 100644 index 000000000000..5df6a1cf2bef --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_TDTO.js @@ -0,0 +1,107 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the set of options for the date and time components is processed correctly. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var locales = [[], ["zh-Hans-CN"], ["hi-IN"], ["en-US"], ["id-ID"]]; +var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))]; + +function testWithDateTimeFormat(options, expected) { + locales.forEach(function (locales) { + var format = new Intl.DateTimeFormat(locales, options); + var resolvedOptions = format.resolvedOptions(); + getDateTimeComponents().forEach(function (component) { + if (resolvedOptions.hasOwnProperty(component)) { + if (!expected.hasOwnProperty(component)) { + $ERROR("Unrequested component " + component + + " added to expected subset " + JSON.stringify(expected) + + "; locales " + locales + ", options " + + (options ? JSON.stringify(options) : options) + "."); + } + } else { + if (expected.hasOwnProperty(component)) { + $ERROR("Missing component " + component + + " from expected subset " + JSON.stringify(expected) + + "; locales " + locales + ", options " + + (options ? JSON.stringify(options) : options) + "."); + } + } + }); + }); +} + +function testWithToLocale(f, options, expected) { + // expected can be either one subset or an array of possible subsets + if (expected.length === undefined) { + expected = [expected]; + } + locales.forEach(function (locales) { + dates.forEach(function (date) { + var formatted = Date.prototype[f].call(date, locales, options); + var expectedStrings = []; + expected.forEach(function (expected) { + var referenceFormat = new Intl.DateTimeFormat(locales, expected); + expectedStrings.push(referenceFormat.format(date)); + }); + if (expectedStrings.indexOf(formatted) === -1) { + $ERROR("Function " + f + " did not return expected string for locales " + + locales + ", options " + (options? JSON.stringify(options) : options) + + "; expected " + + (expectedStrings.length === 1 ? expectedStrings[0] : "one of " + expectedStrings) + + ", got " + formatted + "."); + } + }); + }); +} + +// any/date: steps 5a, 6a, 7a +testWithDateTimeFormat(undefined, {year: "numeric", month: "numeric", day: "numeric"}); + +// any/date: steps 5a, 6a +testWithDateTimeFormat({year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"}); + +// any/date: steps 5a, 6a +testWithDateTimeFormat({hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"}); + +// any/all: steps 5a, 6a, 7a, 8a +testWithToLocale("toLocaleString", undefined, [ + // the first one is not guaranteed to be supported; the second one is + {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}, + {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"} +]); + +// any/all: steps 5a, 6a +testWithToLocale("toLocaleString", {year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"}); + +// any/all: steps 5a, 6a +testWithToLocale("toLocaleString", {hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"}); + +// date/date: steps 5a, 7a +testWithToLocale("toLocaleDateString", undefined, {year: "numeric", month: "numeric", day: "numeric"}); + +// date/date: steps 5a +testWithToLocale("toLocaleDateString", {year: "numeric", month: "numeric"}, {year: "numeric", month: "numeric"}); + +// date/date: steps 5a, 7a +testWithToLocale("toLocaleDateString", {hour: "numeric", minute: "numeric", second: "numeric"}, [ + // the first one is not guaranteed to be supported; the second one is + {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}, + {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"} +]); + +// time/time: steps 6a, 8a +testWithToLocale("toLocaleTimeString", undefined, {hour: "numeric", minute: "numeric", second: "numeric"}); + +// time/time: steps 6a, 8a +testWithToLocale("toLocaleTimeString", {weekday: "short", year: "numeric", month: "numeric", day: "numeric"}, + {weekday: "short", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}); + +// time/time: steps 6a +testWithToLocale("toLocaleTimeString", {hour: "numeric", minute: "numeric"}, {hour: "numeric", minute: "numeric"}); + + diff --git a/js/src/tests/test402/ch12/12.1/12.1.1_a.js b/js/src/tests/test402/ch12/12.1/12.1.1_a.js new file mode 100644 index 000000000000..4f5f3dbf5ee8 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.1_a.js @@ -0,0 +1,18 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that constructing a DateTimeFormat doesn't create or modify + * unwanted properties on the RegExp constructor. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +testForUnwantedRegExpChanges(function () { + new Intl.DateTimeFormat("de-DE-u-ca-gregory"); +}); + +testForUnwantedRegExpChanges(function () { + new Intl.DateTimeFormat("de-DE-u-ca-gregory", {timeZone: "UTC"}); +}); diff --git a/js/src/tests/test402/ch12/12.1/12.1.2.1_4.js b/js/src/tests/test402/ch12/12.1/12.1.2.1_4.js new file mode 100644 index 000000000000..cb22be8f9986 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.2.1_4.js @@ -0,0 +1,21 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that for non-object values passed as this to DateTimeFormat a + * wrapper object will be initialized and returned. + * @author Norbert Lindenberg + */ + +var thisValues = [true, 42, "国際化"]; + +thisValues.forEach(function (value) { + var format = Intl.DateTimeFormat.call(value); + // check that the returned object functions as a date-time format + var referenceFormat = new Intl.DateTimeFormat(); + if (Intl.DateTimeFormat.prototype.format.call(format, new Date(111111111)) !== referenceFormat.format(new Date(111111111))) { + $ERROR("DateTimeFormat initialized from " + value + " doesn't behave like normal date-time format."); + } + return true; +}); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.2.js b/js/src/tests/test402/ch12/12.1/12.1.2.js new file mode 100644 index 000000000000..3ffed2ec82ad --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.2.js @@ -0,0 +1,30 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat can be subclassed. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +// get a date-time format and have it format an array of dates for comparison with the subclass +var locales = ["tlh", "id", "en"]; +var a = [new Date(0), Date.now(), new Date(Date.parse("1989-11-09T17:57:00Z"))]; +var referenceDateTimeFormat = new Intl.DateTimeFormat(locales); +var referenceFormatted = a.map(referenceDateTimeFormat.format); + +function MyDateTimeFormat(locales, options) { + Intl.DateTimeFormat.call(this, locales, options); + // could initialize MyDateTimeFormat properties +} + +MyDateTimeFormat.prototype = Object.create(Intl.DateTimeFormat.prototype); +MyDateTimeFormat.prototype.constructor = MyDateTimeFormat; +// could add methods to MyDateTimeFormat.prototype + +var format = new MyDateTimeFormat(locales); +var actual = a.map(format.format); +testArraysAreSame(referenceFormatted, actual); + diff --git a/js/src/tests/test402/ch12/12.1/12.1.3.js b/js/src/tests/test402/ch12/12.1/12.1.3.js new file mode 100644 index 000000000000..5e70bbb8f3d8 --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1.3.js @@ -0,0 +1,19 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that objects constructed by Intl.DateTimeFormat have the specified internal properties. + * @author Norbert Lindenberg + */ + +var obj = new Intl.DateTimeFormat(); + +var actualPrototype = Object.getPrototypeOf(obj); +if (actualPrototype !== Intl.DateTimeFormat.prototype) { + $ERROR("Prototype of object constructed by Intl.DateTimeFormat isn't Intl.DateTimeFormat.prototype; got " + actualPrototype); +} + +if (!Object.isExtensible(obj)) { + $ERROR("Object constructed by Intl.DateTimeFormat must be extensible."); +} + diff --git a/js/src/tests/test402/ch12/12.1/12.1_L15.js b/js/src/tests/test402/ch12/12.1/12.1_L15.js new file mode 100644 index 000000000000..46c4f5f50b8a --- /dev/null +++ b/js/src/tests/test402/ch12/12.1/12.1_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.DateTimeFormat, true, true, ["supportedLocalesOf"], 0); + diff --git a/js/src/tests/test402/ch12/12.1/browser.js b/js/src/tests/test402/ch12/12.1/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.1/shell.js b/js/src/tests/test402/ch12/12.1/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.2/12.2.1.js b/js/src/tests/test402/ch12/12.2/12.2.1.js new file mode 100644 index 000000000000..3590c0a9d2aa --- /dev/null +++ b/js/src/tests/test402/ch12/12.2/12.2.1.js @@ -0,0 +1,22 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.prototype has the required attributes. + * @author Norbert Lindenberg + */ + +var desc = Object.getOwnPropertyDescriptor(Intl.DateTimeFormat, "prototype"); +if (desc === undefined) { + $ERROR("Intl.DateTimeFormat.prototype is not defined."); +} +if (desc.writable) { + $ERROR("Intl.DateTimeFormat.prototype must not be writable."); +} +if (desc.enumerable) { + $ERROR("Intl.DateTimeFormat.prototype must not be enumerable."); +} +if (desc.configurable) { + $ERROR("Intl.DateTimeFormat.prototype must not be configurable."); +} + diff --git a/js/src/tests/test402/ch12/12.2/12.2.2_L15.js b/js/src/tests/test402/ch12/12.2/12.2.2_L15.js new file mode 100644 index 000000000000..8b21df1fd3a3 --- /dev/null +++ b/js/src/tests/test402/ch12/12.2/12.2.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.supportedLocalesOf + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.DateTimeFormat.supportedLocalesOf, true, false, [], 1); + diff --git a/js/src/tests/test402/ch12/12.2/12.2.2_a.js b/js/src/tests/test402/ch12/12.2/12.2.2_a.js new file mode 100644 index 000000000000..42eedc0a1a30 --- /dev/null +++ b/js/src/tests/test402/ch12/12.2/12.2.2_a.js @@ -0,0 +1,28 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat has a supportedLocalesOf + * property, and it works as planned. + * @author: Roozbeh Pournader + */ + +var defaultLocale = new Intl.DateTimeFormat().resolvedOptions().locale; +var notSupported = 'zxx'; // "no linguistic content" +var requestedLocales = [defaultLocale, notSupported]; + +var supportedLocales; + +if (!Intl.DateTimeFormat.hasOwnProperty('supportedLocalesOf')) { + $ERROR("Intl.DateTimeFormat doesn't have a supportedLocalesOf property."); +} + +supportedLocales = Intl.DateTimeFormat.supportedLocalesOf(requestedLocales); +if (supportedLocales.length !== 1) { + $ERROR('The length of supported locales list is not 1.'); +} + +if (supportedLocales[0] !== defaultLocale) { + $ERROR('The default locale is not returned in the supported list.'); +} + diff --git a/js/src/tests/test402/ch12/12.2/12.2.2_b.js b/js/src/tests/test402/ch12/12.2/12.2.2_b.js new file mode 100644 index 000000000000..06bc8027e7e8 --- /dev/null +++ b/js/src/tests/test402/ch12/12.2/12.2.2_b.js @@ -0,0 +1,13 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.supportedLocalesOf + * doesn't access arguments that it's not given. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintDataProperty(Object.prototype, "1"); +new Intl.DateTimeFormat("und"); diff --git a/js/src/tests/test402/ch12/12.2/12.2.3_b.js b/js/src/tests/test402/ch12/12.2/12.2.3_b.js new file mode 100644 index 000000000000..65fd9dc5fb82 --- /dev/null +++ b/js/src/tests/test402/ch12/12.2/12.2.3_b.js @@ -0,0 +1,47 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat does not accept Unicode locale + * extension keys and values that are not allowed. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var locales = ["ja-JP", "zh-Hans-CN", "zh-Hant-TW"]; +var input = new Date(Date.parse("1989-11-09T17:57:00Z")); + +locales.forEach(function (locale) { + var defaultDateTimeFormat = new Intl.DateTimeFormat([locale]); + var defaultOptions = defaultDateTimeFormat.resolvedOptions(); + var defaultOptionsJSON = JSON.stringify(defaultOptions); + var defaultLocale = defaultOptions.locale; + var defaultFormatted = defaultDateTimeFormat.format(input); + + var keyValues = { + "cu": ["USD", "EUR", "JPY", "CNY", "TWD", "invalid"], // DateTimeFormat internally uses NumberFormat + "nu": ["native", "traditio", "finance", "invalid"], + "tz": ["usnavajo", "utcw01", "aumel", "uslax", "usnyc", "deber", "invalid"] + }; + + Object.getOwnPropertyNames(keyValues).forEach(function (key) { + keyValues[key].forEach(function (value) { + var dateTimeFormat = new Intl.DateTimeFormat([locale + "-u-" + key + "-" + value]); + var options = dateTimeFormat.resolvedOptions(); + if (options.locale !== defaultLocale) { + $ERROR("Locale " + options.locale + " is affected by key " + + key + "; value " + value + "."); + } + if (JSON.stringify(options) !== defaultOptionsJSON) { + $ERROR("Resolved options " + JSON.stringify(options) + " are affected by key " + + key + "; value " + value + "."); + } + if (defaultFormatted !== dateTimeFormat.format(input)) { + $ERROR("Formatted value " + dateTimeFormat.format(input) + " is affected by key " + + key + "; value " + value + "."); + } + }); + }); +}); + diff --git a/js/src/tests/test402/ch12/12.2/12.2.3_c.js b/js/src/tests/test402/ch12/12.2/12.2.3_c.js new file mode 100644 index 000000000000..0aced6ca91a5 --- /dev/null +++ b/js/src/tests/test402/ch12/12.2/12.2.3_c.js @@ -0,0 +1,52 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat provides the required date-time + * format component subsets. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var locales = ["de-DE", "en-US", "hi-IN", "id-ID", "ja-JP", "th-TH", "zh-Hans-CN", "zh-Hant-TW", "zxx"]; +var subsets = [ + {weekday: "long", year: "numeric", month: "numeric", day: "numeric", + hour: "numeric", minute: "numeric", second: "numeric"}, + {weekday: "long", year: "numeric", month: "numeric", day: "numeric"}, + {year: "numeric", month: "numeric", day: "numeric"}, + {year: "numeric", month: "numeric"}, + {month: "numeric", day: "numeric"}, + {hour: "numeric", minute: "numeric", second: "numeric"}, + {hour: "numeric", minute: "numeric"} +]; + +locales.forEach(function (locale) { + subsets.forEach(function (subset) { + var format = new Intl.DateTimeFormat([locale], subset); + var actual = format.resolvedOptions(); + getDateTimeComponents().forEach(function (component) { + if (actual.hasOwnProperty(component)) { + if (!subset.hasOwnProperty(component)) { + $ERROR("Unrequested component " + component + + " added to requested subset " + JSON.stringify(subset) + + "; locale " + locale + "."); + } + try { + testValidDateTimeComponentValue(component, actual[component]); + } catch (e) { + e.message += " (Testing locale " + locale + "; subset " + + JSON.stringify(subset) + ")"; + throw e; + } + } else { + if (subset.hasOwnProperty(component)) { + $ERROR("Missing component " + component + + " from requested subset " + JSON.stringify(subset) + + "; locale " + locale + "."); + } + } + }); + }); +}); + diff --git a/js/src/tests/test402/ch12/12.2/browser.js b/js/src/tests/test402/ch12/12.2/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.2/shell.js b/js/src/tests/test402/ch12/12.2/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.3/12.3.1.js b/js/src/tests/test402/ch12/12.3/12.3.1.js new file mode 100644 index 000000000000..1755dd64bc1f --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.1.js @@ -0,0 +1,14 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.prototype.constructor is the + * Intl.DateTimeFormat. + * @author: Roozbeh Pournader + */ + +if (Intl.DateTimeFormat.prototype.constructor !== Intl.DateTimeFormat) { + $ERROR("Intl.DateTimeFormat.prototype.constructor is not the same as " + + "Intl.DateTimeFormat"); +} + diff --git a/js/src/tests/test402/ch12/12.3/12.3.2_1_a_L15.js b/js/src/tests/test402/ch12/12.3/12.3.2_1_a_L15.js new file mode 100644 index 000000000000..2fb768d09c2d --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.2_1_a_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the function returned by Intl.DateTimeFormat.prototype.format + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(new Intl.DateTimeFormat().format, true, false, [], 0); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.2_1_c.js b/js/src/tests/test402/ch12/12.3/12.3.2_1_c.js new file mode 100644 index 000000000000..d4b9f891fe47 --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.2_1_c.js @@ -0,0 +1,34 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that format function is bound to its Intl.DateTimeFormat. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))]; +var locales = [undefined, ["de"], ["th-u-ca-gregory-nu-thai"], ["en"], ["ja-u-ca-japanese"], ["ar-u-ca-islamicc-nu-arab"]]; +var options = [ + undefined, + {hour12: false}, + {month: "long", day: "numeric", hour: "2-digit", minute: "2-digit"} +]; + +locales.forEach(function (locales) { + options.forEach(function (options) { + var formatObj = new Intl.DateTimeFormat(locales, options); + var formatFunc = formatObj.format; + dates.forEach(function (date) { + var referenceFormatted = formatObj.format(date); + var formatted = formatFunc(date); + if (referenceFormatted !== formatted) { + $ERROR("format function produces different result than format method for locales " + + locales + "; options: " + (options ? JSON.stringify(options) : options) + + " : " + formatted + " vs. " + referenceFormatted + "."); + } + }); + }); +}); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.2_FDT_1.js b/js/src/tests/test402/ch12/12.3/12.3.2_FDT_1.js new file mode 100644 index 000000000000..d643d7928b2f --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.2_FDT_1.js @@ -0,0 +1,26 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that format handles non-finite values correctly. + * @author Norbert Lindenberg + */ + +var invalidValues = [NaN, Infinity, -Infinity]; + +var format = new Intl.DateTimeFormat(); + +invalidValues.forEach(function (value) { + var error; + try { + var result = format.format(value); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid value " + value + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid value " + value + " was rejected with wrong error " + error.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.2_FDT_7_a_iv.js b/js/src/tests/test402/ch12/12.3/12.3.2_FDT_7_a_iv.js new file mode 100644 index 000000000000..f13878403954 --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.2_FDT_7_a_iv.js @@ -0,0 +1,32 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that format uses a proleptic Gregorian calendar with no year 0. + * @author Norbert Lindenberg + */ + +var dates = [ + 0, // January 1, 1970 + -62151602400000, // in June 1 BC + -8640000000000000 // beginning of ECMAScript time +]; + +var format = new Intl.DateTimeFormat(["en-US"], {year: "numeric", month: "long", timeZone: "UTC"}); + +// this test requires a Gregorian calendar, which we usually find in the US +if (format.resolvedOptions().calendar !== "gregory") { + $ERROR("Internal error: Didn't find Gregorian calendar"); +} + +dates.forEach(function (date) { + var year = new Date(date).getUTCFullYear(); + var expectedYear = year <= 0 ? 1 - year : year; + var expectedYearString = expectedYear.toLocaleString(["en-US"], {useGrouping: false}); + var dateString = format.format(date); + if (dateString.indexOf(expectedYearString) === -1) { + $ERROR("Formatted year doesn't contain expected year – expected " + + expectedYearString + ", got " + dateString + "."); + } +}); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.2_L15.js b/js/src/tests/test402/ch12/12.3/12.3.2_L15.js new file mode 100644 index 000000000000..73d309e26abc --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the getter for Intl.DateTimeFormat.prototype.format + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format").get , true, false, [], 0); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.2_TLT_2.js b/js/src/tests/test402/ch12/12.3/12.3.2_TLT_2.js new file mode 100644 index 000000000000..bf0a8ed36fd6 --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.2_TLT_2.js @@ -0,0 +1,16 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that the behavior of a Record is not affected by adversarial + * changes to Object.prototype. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintProperties(["weekday", "era", "year", "month", "day", "hour", "minute", "second", "inDST"]); + +var format = new Intl.DateTimeFormat(); +var time = format.format(); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.3.js b/js/src/tests/test402/ch12/12.3/12.3.3.js new file mode 100644 index 000000000000..b5735c3500e1 --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.3.js @@ -0,0 +1,52 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that the object returned by Intl.DateTimeFormat.prototype.resolvedOptions + * has the right properties. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var actual = new Intl.DateTimeFormat().resolvedOptions(); + +var actual2 = new Intl.DateTimeFormat().resolvedOptions(); +if (actual2 === actual) { + $ERROR("resolvedOptions returned the same object twice."); +} + +// source: CLDR file common/bcp47/calendar.xml; version CLDR 21. +var calendars = [ + "buddhist", + "chinese", + "coptic", + "ethioaa", + "ethiopic", + "gregory", + "hebrew", + "indian", + "islamic", + "islamicc", + "iso8601", + "japanese", + "persian", + "roc" +]; + +// this assumes the default values where the specification provides them +mustHaveProperty(actual, "locale", isCanonicalizedStructurallyValidLanguageTag); +mustHaveProperty(actual, "calendar", calendars); +mustHaveProperty(actual, "numberingSystem", isValidNumberingSystem); +mustHaveProperty(actual, "timeZone", [undefined]); +mustNotHaveProperty(actual, "weekday"); +mustNotHaveProperty(actual, "era"); +mustHaveProperty(actual, "year", ["2-digit", "numeric"]); +mustHaveProperty(actual, "month", ["2-digit", "numeric", "narrow", "short", "long"]); +mustHaveProperty(actual, "day", ["2-digit", "numeric"]); +mustNotHaveProperty(actual, "hour"); +mustNotHaveProperty(actual, "minute"); +mustNotHaveProperty(actual, "second"); +mustNotHaveProperty(actual, "timeZoneName"); +mustNotHaveProperty(actual, "hour12"); + diff --git a/js/src/tests/test402/ch12/12.3/12.3.3_L15.js b/js/src/tests/test402/ch12/12.3/12.3.3_L15.js new file mode 100644 index 000000000000..1b4079ebec8f --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.prototype.resolvedOptions + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.DateTimeFormat.prototype.resolvedOptions, true, false, [], 0); + diff --git a/js/src/tests/test402/ch12/12.3/12.3_L15.js b/js/src/tests/test402/ch12/12.3/12.3_L15.js new file mode 100644 index 000000000000..55f1c16ca1e7 --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.prototype + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Intl.DateTimeFormat.prototype, false, false, ["constructor", "format", "resolvedOptions"]); + diff --git a/js/src/tests/test402/ch12/12.3/12.3_a.js b/js/src/tests/test402/ch12/12.3/12.3_a.js new file mode 100644 index 000000000000..e1d795b910de --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3_a.js @@ -0,0 +1,16 @@ +// Copyright 2012 Google Inc. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.prototype is an object that + * has been initialized as an Intl.DateTimeFormat. + * @author: Roozbeh Pournader + */ + +// test by calling a function that would fail if "this" were not an object +// initialized as an Intl.DateTimeFormat +if (typeof Intl.DateTimeFormat.prototype.format(0) !== "string") { + $ERROR("Intl.DateTimeFormat's prototype is not an object that has been " + + "initialized as an Intl.DateTimeFormat"); +} + diff --git a/js/src/tests/test402/ch12/12.3/12.3_b.js b/js/src/tests/test402/ch12/12.3/12.3_b.js new file mode 100644 index 000000000000..d905bf5712ab --- /dev/null +++ b/js/src/tests/test402/ch12/12.3/12.3_b.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat.prototype functions throw a + * TypeError if called on a non-object value or an object that hasn't been + * initialized as a DateTimeFormat. + * @author Norbert Lindenberg + */ + +var functions = { + "format getter": Object.getOwnPropertyDescriptor(Intl.DateTimeFormat.prototype, "format").get, + resolvedOptions: Intl.DateTimeFormat.prototype.resolvedOptions +}; +var invalidTargets = [undefined, null, true, 0, "DateTimeFormat", [], {}]; + +Object.getOwnPropertyNames(functions).forEach(function (functionName) { + var f = functions[functionName]; + invalidTargets.forEach(function (target) { + var error; + try { + f.call(target); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Calling " + functionName + " on " + target + " was not rejected."); + } else if (error.name !== "TypeError") { + $ERROR("Calling " + functionName + " on " + target + " was rejected with wrong error " + error.name + "."); + } + }); +}); + diff --git a/js/src/tests/test402/ch12/12.3/browser.js b/js/src/tests/test402/ch12/12.3/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.3/shell.js b/js/src/tests/test402/ch12/12.3/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.4/12.4_a.js b/js/src/tests/test402/ch12/12.4/12.4_a.js new file mode 100644 index 000000000000..8e8d5954c0ba --- /dev/null +++ b/js/src/tests/test402/ch12/12.4/12.4_a.js @@ -0,0 +1,15 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Intl.DateTimeFormat instances have the specified properties. + * @author Norbert Lindenberg + */ + +var obj = new Intl.DateTimeFormat(); + +var toStringValue = Object.prototype.toString.call(obj); +if (toStringValue !== "[object Object]") { + $ERROR("Intl.DateTimeFormat instance produces wrong [[Class]] - toString returns " + toStringValue + "."); +} + diff --git a/js/src/tests/test402/ch12/12.4/browser.js b/js/src/tests/test402/ch12/12.4/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/12.4/shell.js b/js/src/tests/test402/ch12/12.4/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/browser.js b/js/src/tests/test402/ch12/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch12/shell.js b/js/src/tests/test402/ch12/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_1.js b/js/src/tests/test402/ch13/13.1/13.1.1_1.js new file mode 100644 index 000000000000..37be9711b34f --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_1.js @@ -0,0 +1,24 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that localeCompare rejects values that can't be coerced to an object. + * @author Norbert Lindenberg + */ + +var invalidValues = [undefined, null]; + +invalidValues.forEach(function (value) { + var error; + try { + var result = String.prototype.localeCompare.call(value, ""); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("String.prototype.localeCompare did not reject this = " + value + "."); + } else if (error.name !== "TypeError") { + $ERROR("String.prototype.localeCompare rejected this = " + value + " with wrong error " + error.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_2.js b/js/src/tests/test402/ch13/13.1/13.1.1_2.js new file mode 100644 index 000000000000..bad7c0fdd847 --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_2.js @@ -0,0 +1,26 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that localeCompare coerces this to a string. + * @author Norbert Lindenberg + */ + +var thisValues = [true, 5, "hello", {toString: function () { return "good bye"; }}]; +var thatValues = ["true", "5", "hello", "good bye"]; + +var i; +for (i = 0; i < thisValues.length; i++) { + var j; + for (j = 0; j < thatValues.length; j++) { + var result = String.prototype.localeCompare.call(thisValues[i], thatValues[j]); + if ((result === 0) !== (i === j)) { + if (result === 0) { + $ERROR("localeCompare treats " + thisValues[i] + " and " + thatValues[j] + " as equal."); + } else { + $ERROR("localeCompare treats " + thisValues[i] + " and " + thatValues[j] + " as different."); + } + } + } +} + diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_3_1.js b/js/src/tests/test402/ch13/13.1/13.1.1_3_1.js new file mode 100644 index 000000000000..113a2d9aa872 --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_3_1.js @@ -0,0 +1,26 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that localeCompare coerces that to a string. + * @author Norbert Lindenberg + */ + +var thisValues = ["true", "5", "hello", "good bye"]; +var thatValues = [true, 5, "hello", {toString: function () { return "good bye"; }}]; + +var i; +for (i = 0; i < thisValues.length; i++) { + var j; + for (j = 0; j < thatValues.length; j++) { + var result = String.prototype.localeCompare.call(thisValues[i], thatValues[j]); + if ((result === 0) !== (i === j)) { + if (result === 0) { + $ERROR("localeCompare treats " + thisValues[i] + " and " + thatValues[j] + " as equal."); + } else { + $ERROR("localeCompare treats " + thisValues[i] + " and " + thatValues[j] + " as different."); + } + } + } +} + diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_3_2.js b/js/src/tests/test402/ch13/13.1/13.1.1_3_2.js new file mode 100644 index 000000000000..441166c9fb03 --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_3_2.js @@ -0,0 +1,22 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that String.prototype.localeCompare treats a missing + * "that" argument, undefined, and "undefined" as equivalent. + * @author Norbert Lindenberg + */ + +var thisValues = ["a", "t", "u", "undefined", "UNDEFINED", "nicht definiert", "xyz", "未定义"]; + +var i; +for (i = 0; i < thisValues.length; i++) { + var thisValue = thisValues[i]; + if (thisValue.localeCompare() !== thisValue.localeCompare(undefined)) { + $ERROR("String.prototype.localeCompare does not treat missing 'that' argument as undefined."); + } + if (thisValue.localeCompare(undefined) !== thisValue.localeCompare("undefined")) { + $ERROR("String.prototype.localeCompare does not treat undefined 'that' argument as \"undefined\"."); + } +} + diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_6_1.js b/js/src/tests/test402/ch13/13.1/13.1.1_6_1.js new file mode 100644 index 000000000000..30607d317164 --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_6_1.js @@ -0,0 +1,65 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that String.prototype.localeCompare throws the same exceptions as Intl.Collator. + * @author Norbert Lindenberg + */ + +var locales = [null, [NaN], ["i"], ["de_DE"]]; +var options = [ + {localeMatcher: null}, + {usage: "invalid"}, + {sensitivity: "invalid"} +]; + +locales.forEach(function (locales) { + var referenceError, error; + try { + var collator = new Intl.Collator(locales); + } catch (e) { + referenceError = e; + } + if (referenceError === undefined) { + $ERROR("Internal error: Expected exception was not thrown by Intl.Collator for locales " + locales + "."); + } + + try { + var result = "".localeCompare("", locales); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("String.prototype.localeCompare didn't throw exception for locales " + locales + "."); + } else if (error.name !== referenceError.name) { + $ERROR("String.prototype.localeCompare threw exception " + error.name + + " for locales " + locales + "; expected " + referenceError.name + "."); + } +}); + +options.forEach(function (options) { + var referenceError, error; + try { + var collator = new Intl.Collator([], options); + } catch (e) { + referenceError = e; + } + if (referenceError === undefined) { + $ERROR("Internal error: Expected exception was not thrown by Intl.Collator for options " + + JSON.stringify(options) + "."); + } + + try { + var result = "".localeCompare("", [], options); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("String.prototype.localeCompare didn't throw exception for options " + + JSON.stringify(options) + "."); + } else if (error.name !== referenceError.name) { + $ERROR("String.prototype.localeCompare threw exception " + error.name + + " for options " + JSON.stringify(options) + "; expected " + referenceError.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_6_2.js b/js/src/tests/test402/ch13/13.1/13.1.1_6_2.js new file mode 100644 index 000000000000..481a7803b2fa --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_6_2.js @@ -0,0 +1,13 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that String.prototype.localeCompare uses the standard + * built-in Intl.Collator constructor. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintDataProperty(Intl, "Collator"); +"a".localeCompare("b"); diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_7.js b/js/src/tests/test402/ch13/13.1/13.1.1_7.js new file mode 100644 index 000000000000..f0c588f64c3d --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_7.js @@ -0,0 +1,33 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that localeCompare produces the same results as Intl.Collator. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var strings = ["d", "O", "od", "oe", "of", "ö", "o\u0308", "X", "y", "Z", "Z.", "𠮷野家", "吉野家", "!A", "A", "b", "C"]; +var locales = [undefined, ["de"], ["de-u-co-phonebk"], ["en"], ["ja"], ["sv"]]; +var options = [ + undefined, + {usage: "search"}, + {sensitivity: "base", ignorePunctuation: true} +]; + +locales.forEach(function (locales) { + options.forEach(function (options) { + var referenceCollator = new Intl.Collator(locales, options); + var referenceSorted = strings.slice().sort(referenceCollator.compare); + + strings.sort(function (a, b) { return a.localeCompare(b, locales, options); }); + try { + testArraysAreSame(referenceSorted, strings); + } catch (e) { + e.message += " (Testing with locales " + locales + "; options " + JSON.stringify(options) + ".)"; + throw e; + } + }); +}); + diff --git a/js/src/tests/test402/ch13/13.1/13.1.1_L15.js b/js/src/tests/test402/ch13/13.1/13.1.1_L15.js new file mode 100644 index 000000000000..d921de00052a --- /dev/null +++ b/js/src/tests/test402/ch13/13.1/13.1.1_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that String.prototype.localeCompare + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(String.prototype.localeCompare, true, false, [], 1); + diff --git a/js/src/tests/test402/ch13/13.1/browser.js b/js/src/tests/test402/ch13/13.1/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/13.1/shell.js b/js/src/tests/test402/ch13/13.1/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/13.2/13.2.1_1.js b/js/src/tests/test402/ch13/13.2/13.2.1_1.js new file mode 100644 index 000000000000..da1ee8fe58f4 --- /dev/null +++ b/js/src/tests/test402/ch13/13.2/13.2.1_1.js @@ -0,0 +1,37 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that toLocaleString handles "this Number value" correctly. + * @author Norbert Lindenberg + */ + +var invalidValues = [undefined, null, "5", false, {valueOf: function () { return 5; }}]; +var validValues = [5, NaN, -1234567.89, -Infinity]; + +invalidValues.forEach(function (value) { + var error; + try { + var result = Number.prototype.toLocaleString.call(value); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Number.prototype.toLocaleString did not reject this = " + value + "."); + } else if (error.name !== "TypeError") { + $ERROR("Number.prototype.toLocaleString rejected this = " + value + " with wrong error " + error.name + "."); + } +}); + +// for valid values, just check that a Number value and the corresponding +// Number object get the same result. +validValues.forEach(function (value) { + var Constructor = Number; // to keep jshint happy + var valueResult = Number.prototype.toLocaleString.call(value); + var objectResult = Number.prototype.toLocaleString.call(new Constructor(value)); + if (valueResult !== objectResult) { + $ERROR("Number.prototype.toLocaleString produces different results for Number value " + + value + " and corresponding Number object: " + valueResult + " vs. " + objectResult + "."); + } +}); + diff --git a/js/src/tests/test402/ch13/13.2/13.2.1_4_1.js b/js/src/tests/test402/ch13/13.2/13.2.1_4_1.js new file mode 100644 index 000000000000..e6e0b11638a3 --- /dev/null +++ b/js/src/tests/test402/ch13/13.2/13.2.1_4_1.js @@ -0,0 +1,67 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Number.prototype.toLocaleString throws the same exceptions as Intl.NumberFormat. + * @author Norbert Lindenberg + */ + +var locales = [null, [NaN], ["i"], ["de_DE"]]; +var options = [ + {localeMatcher: null}, + {style: "invalid"}, + {style: "currency"}, + {style: "currency", currency: "ßP"}, + {maximumSignificantDigits: -Infinity} +]; + +locales.forEach(function (locales) { + var referenceError, error; + try { + var format = new Intl.NumberFormat(locales); + } catch (e) { + referenceError = e; + } + if (referenceError === undefined) { + $ERROR("Internal error: Expected exception was not thrown by Intl.NumberFormat for locales " + locales + "."); + } + + try { + var result = (0).toLocaleString(locales); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Number.prototype.toLocaleString didn't throw exception for locales " + locales + "."); + } else if (error.name !== referenceError.name) { + $ERROR("Number.prototype.toLocaleString threw exception " + error.name + + " for locales " + locales + "; expected " + referenceError.name + "."); + } +}); + +options.forEach(function (options) { + var referenceError, error; + try { + var format = new Intl.NumberFormat([], options); + } catch (e) { + referenceError = e; + } + if (referenceError === undefined) { + $ERROR("Internal error: Expected exception was not thrown by Intl.NumberFormat for options " + + JSON.stringify(options) + "."); + } + + try { + var result = (0).toLocaleString([], options); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Number.prototype.toLocaleString didn't throw exception for options " + + JSON.stringify(options) + "."); + } else if (error.name !== referenceError.name) { + $ERROR("Number.prototype.toLocaleString threw exception " + error.name + + " for options " + JSON.stringify(options) + "; expected " + referenceError.name + "."); + } +}); + diff --git a/js/src/tests/test402/ch13/13.2/13.2.1_4_2.js b/js/src/tests/test402/ch13/13.2/13.2.1_4_2.js new file mode 100644 index 000000000000..a79cfffde782 --- /dev/null +++ b/js/src/tests/test402/ch13/13.2/13.2.1_4_2.js @@ -0,0 +1,13 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Number.prototype.toLocaleString uses the standard + * built-in Intl.NumberFormat constructor. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintDataProperty(Intl, "NumberFormat"); +(0.0).toLocaleString(); diff --git a/js/src/tests/test402/ch13/13.2/13.2.1_5.js b/js/src/tests/test402/ch13/13.2/13.2.1_5.js new file mode 100644 index 000000000000..eb953b64d4c4 --- /dev/null +++ b/js/src/tests/test402/ch13/13.2/13.2.1_5.js @@ -0,0 +1,41 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Number.prototype.toLocaleString produces the same results as Intl.NumberFormat. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var numbers = [0, -0, 1, -1, 5.5, 123, -123, -123.45, 123.44501, 0.001234, + -0.00000000123, 0.00000000000000000000000000000123, 1.2, 0.0000000012344501, + 123445.01, 12344501000000000000000000000000000, -12344501000000000000000000000000000, + Infinity, -Infinity, NaN]; +var locales = [undefined, ["de"], ["th-u-nu-thai"], ["en"], ["ja-u-nu-jpanfin"], ["ar-u-nu-arab"]]; +var options = [ + undefined, + {style: "percent"}, + {style: "currency", currency: "EUR", currencyDisplay: "symbol"}, + {style: "currency", currency: "IQD", currencyDisplay: "symbol"}, + {style: "currency", currency: "KMF", currencyDisplay: "symbol"}, + {style: "currency", currency: "CLF", currencyDisplay: "symbol"}, + {useGrouping: false, minimumIntegerDigits: 3, minimumFractionDigits: 1, maximumFractionDigits: 3} +]; + +locales.forEach(function (locales) { + options.forEach(function (options) { + var referenceNumberFormat = new Intl.NumberFormat(locales, options); + var referenceFormatted = numbers.map(referenceNumberFormat.format); + + var formatted = numbers.map(function (a) { return a.toLocaleString(locales, options); }); + try { + testArraysAreSame(referenceFormatted, formatted); + } catch (e) { + e.message += " (Testing with locales " + locales + "; options " + + (options ? JSON.stringify(options) : options) + ".)"; + throw e; + } + }); +}); + diff --git a/js/src/tests/test402/ch13/13.2/13.2.1_L15.js b/js/src/tests/test402/ch13/13.2/13.2.1_L15.js new file mode 100644 index 000000000000..8b53f749635b --- /dev/null +++ b/js/src/tests/test402/ch13/13.2/13.2.1_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Number.prototype.toLocaleString + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Number.prototype.toLocaleString, true, false, [], 0); + diff --git a/js/src/tests/test402/ch13/13.2/browser.js b/js/src/tests/test402/ch13/13.2/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/13.2/shell.js b/js/src/tests/test402/ch13/13.2/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/13.3/13.3.0_1.js b/js/src/tests/test402/ch13/13.3/13.3.0_1.js new file mode 100644 index 000000000000..0f2902162e42 --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.0_1.js @@ -0,0 +1,32 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleString & Co. handle "this time value" correctly. + * @author Norbert Lindenberg + */ + +var functions = { + toLocaleString: Date.prototype.toLocaleString, + toLocaleDateString: Date.prototype.toLocaleDateString, + toLocaleTimeString: Date.prototype.toLocaleTimeString +}; +var invalidValues = [undefined, null, 5, "5", false, {valueOf: function () { return 5; }}]; + +Object.getOwnPropertyNames(functions).forEach(function (p) { + var f = functions[p]; + invalidValues.forEach(function (value) { + var error; + try { + var result = f.call(value); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Date.prototype." + p + " did not reject this = " + value + "."); + } else if (error.name !== "TypeError") { + $ERROR("Date.prototype." + p + " rejected this = " + value + " with wrong error " + error.name + "."); + } + }); +}); + diff --git a/js/src/tests/test402/ch13/13.3/13.3.0_2.js b/js/src/tests/test402/ch13/13.3/13.3.0_2.js new file mode 100644 index 000000000000..7d5f32fa6866 --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.0_2.js @@ -0,0 +1,26 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleString & Co. handle non-finite values correctly. + * @author Norbert Lindenberg + */ + +var functions = { + toLocaleString: Date.prototype.toLocaleString, + toLocaleDateString: Date.prototype.toLocaleDateString, + toLocaleTimeString: Date.prototype.toLocaleTimeString +}; +var invalidValues = [NaN, Infinity, -Infinity]; + +Object.getOwnPropertyNames(functions).forEach(function (p) { + var f = functions[p]; + invalidValues.forEach(function (value) { + var result = f.call(new Date(value)); + if (result !== "Invalid Date") { + $ERROR("Date.prototype." + p + " did not return \"Invalid Date\" for " + + value + " – got " + result + " instead."); + } + }); +}); + diff --git a/js/src/tests/test402/ch13/13.3/13.3.0_6_1.js b/js/src/tests/test402/ch13/13.3/13.3.0_6_1.js new file mode 100644 index 000000000000..c97b240b478d --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.0_6_1.js @@ -0,0 +1,74 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleString & Co. throws the same exceptions as Intl.DateTimeFormat. + * @author Norbert Lindenberg + */ + +var functions = { + toLocaleString: Date.prototype.toLocaleString, + toLocaleDateString: Date.prototype.toLocaleDateString, + toLocaleTimeString: Date.prototype.toLocaleTimeString +}; +var locales = [null, [NaN], ["i"], ["de_DE"]]; +var options = [ + {localeMatcher: null}, + {timeZone: "invalid"}, + {hour: "long"}, + {formatMatcher: "invalid"} +]; + +Object.getOwnPropertyNames(functions).forEach(function (p) { + var f = functions[p]; + locales.forEach(function (locales) { + var referenceError, error; + try { + var format = new Intl.DateTimeFormat(locales); + } catch (e) { + referenceError = e; + } + if (referenceError === undefined) { + $ERROR("Internal error: Expected exception was not thrown by Intl.DateTimeFormat for locales " + locales + "."); + } + + try { + var result = f.call(new Date(), locales); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Date.prototype." + p + " didn't throw exception for locales " + locales + "."); + } else if (error.name !== referenceError.name) { + $ERROR("Date.prototype." + p + " threw exception " + error.name + + " for locales " + locales + "; expected " + referenceError.name + "."); + } + }); + + options.forEach(function (options) { + var referenceError, error; + try { + var format = new Intl.DateTimeFormat([], options); + } catch (e) { + referenceError = e; + } + if (referenceError === undefined) { + $ERROR("Internal error: Expected exception was not thrown by Intl.DateTimeFormat for options " + + JSON.stringify(options) + "."); + } + + try { + var result = f.call(new Date(), [], options); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Date.prototype." + p + " didn't throw exception for options " + + JSON.stringify(options) + "."); + } else if (error.name !== referenceError.name) { + $ERROR("Date.prototype." + p + " threw exception " + error.name + + " for options " + JSON.stringify(options) + "; expected " + referenceError.name + "."); + } + }); +}); + diff --git a/js/src/tests/test402/ch13/13.3/13.3.0_6_2.js b/js/src/tests/test402/ch13/13.3/13.3.0_6_2.js new file mode 100644 index 000000000000..dcce05906649 --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.0_6_2.js @@ -0,0 +1,15 @@ +// Copyright 2013 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleString & Co. use the standard + * built-in Intl.DateTimeFormat constructor. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +taintDataProperty(Intl, "DateTimeFormat"); +new Date().toLocaleString(); +new Date().toLocaleDateString(); +new Date().toLocaleTimeString(); diff --git a/js/src/tests/test402/ch13/13.3/13.3.0_7.js b/js/src/tests/test402/ch13/13.3/13.3.0_7.js new file mode 100644 index 000000000000..fe7c9271d0cf --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.0_7.js @@ -0,0 +1,58 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleString & Co. produces the same results as Intl.DateTimeFormat. + * @author Norbert Lindenberg + */ + +$INCLUDE("testIntl.js"); + +var functions = { + toLocaleString: [Date.prototype.toLocaleString, + {year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"}], + toLocaleDateString: [Date.prototype.toLocaleDateString, + {year: "numeric", month: "numeric", day: "numeric"}], + toLocaleTimeString: [Date.prototype.toLocaleTimeString, + {hour: "numeric", minute: "numeric", second: "numeric"}] +}; +var dates = [new Date(), new Date(0), new Date(Date.parse("1989-11-09T17:57:00Z"))]; +var locales = [undefined, ["de"], ["th-u-ca-gregory-nu-thai"], ["en"], ["ja-u-ca-japanese"], ["ar-u-ca-islamicc-nu-arab"]]; +var options = [ + undefined, + {hour12: false}, + {month: "long", day: "numeric", hour: "2-digit", minute: "2-digit"} +]; + +Object.getOwnPropertyNames(functions).forEach(function (p) { + var f = functions[p][0]; + var defaults = functions[p][1]; + locales.forEach(function (locales) { + options.forEach(function (options) { + var constructorOptions = options; + if (options === undefined) { + constructorOptions = defaults; + } else if (options.day === undefined) { + // for simplicity, our options above have either both date and time or neither + constructorOptions = Object.create(defaults); + for (var prop in options) { + if (options.hasOwnProperty(prop)) { + constructorOptions[prop] = options[prop]; + } + } + } + var referenceDateTimeFormat = new Intl.DateTimeFormat(locales, constructorOptions); + var referenceFormatted = dates.map(referenceDateTimeFormat.format); + + var formatted = dates.map(function (a) { return f.call(a, locales, options); }); + try { + testArraysAreSame(referenceFormatted, formatted); + } catch (e) { + e.message += " (Testing with locales " + locales + "; options " + + (options ? JSON.stringify(options) : options) + ".)"; + throw e; + } + }); + }); +}); + diff --git a/js/src/tests/test402/ch13/13.3/13.3.1_L15.js b/js/src/tests/test402/ch13/13.3/13.3.1_L15.js new file mode 100644 index 000000000000..a8c697c077df --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.1_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleString + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Date.prototype.toLocaleString, true, false, [], 0); + diff --git a/js/src/tests/test402/ch13/13.3/13.3.2_L15.js b/js/src/tests/test402/ch13/13.3/13.3.2_L15.js new file mode 100644 index 000000000000..5eeed944ea45 --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.2_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleDateString + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Date.prototype.toLocaleDateString, true, false, [], 0); + diff --git a/js/src/tests/test402/ch13/13.3/13.3.3_L15.js b/js/src/tests/test402/ch13/13.3/13.3.3_L15.js new file mode 100644 index 000000000000..dac7c3513116 --- /dev/null +++ b/js/src/tests/test402/ch13/13.3/13.3.3_L15.js @@ -0,0 +1,14 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the license found in the LICENSE file. + +/** + * @description Tests that Date.prototype.toLocaleTimeString + * meets the requirements for built-in objects defined by the introduction of + * chapter 15 of the ECMAScript Language Specification. + * @author Norbert Lindenberg + */ + +$INCLUDE("testBuiltInObject.js"); + +testBuiltInObject(Date.prototype.toLocaleTimeString, true, false, [], 0); + diff --git a/js/src/tests/test402/ch13/13.3/browser.js b/js/src/tests/test402/ch13/13.3/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/13.3/shell.js b/js/src/tests/test402/ch13/13.3/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/browser.js b/js/src/tests/test402/ch13/browser.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/ch13/shell.js b/js/src/tests/test402/ch13/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/test402/lib/testBuiltInObject.js b/js/src/tests/test402/lib/testBuiltInObject.js new file mode 100644 index 000000000000..3a8d24fdc462 --- /dev/null +++ b/js/src/tests/test402/lib/testBuiltInObject.js @@ -0,0 +1,124 @@ +// Copyright 2012 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * @description Tests that obj meets the requirements for built-in objects + * defined by the introduction of chapter 15 of the ECMAScript Language Specification. + * @param {Object} obj the object to be tested. + * @param {boolean} isFunction whether the specification describes obj as a function. + * @param {boolean} isConstructor whether the specification describes obj as a constructor. + * @param {String[]} properties an array with the names of the built-in properties of obj, + * excluding length, prototype, or properties with non-default attributes. + * @param {number} length for functions only: the length specified for the function + * or derived from the argument list. + * @author Norbert Lindenberg + */ + +function testBuiltInObject(obj, isFunction, isConstructor, properties, length) { + + if (obj === undefined) { + $ERROR("Object being tested is undefined."); + } + + var objString = Object.prototype.toString.call(obj); + if (isFunction) { + if (objString !== "[object Function]") { + $ERROR("The [[Class]] internal property of a built-in function must be " + + "\"Function\", but toString() returns " + objString); + } + } else { + if (objString !== "[object Object]") { + $ERROR("The [[Class]] internal property of a built-in non-function object must be " + + "\"Object\", but toString() returns " + objString); + } + } + + if (!Object.isExtensible(obj)) { + $ERROR("Built-in objects must be extensible."); + } + + if (isFunction && Object.getPrototypeOf(obj) !== Function.prototype) { + $ERROR("Built-in functions must have Function.prototype as their prototype."); + } + + if (isConstructor && Object.getPrototypeOf(obj.prototype) !== Object.prototype) { + $ERROR("Built-in prototype objects must have Object.prototype as their prototype."); + } + + // verification of the absence of the [[Construct]] internal property has + // been moved to the end of the test + + // verification of the absence of the prototype property has + // been moved to the end of the test + + if (isFunction) { + + if (typeof obj.length !== "number" || obj.length !== Math.floor(obj.length)) { + $ERROR("Built-in functions must have a length property with an integer value."); + } + + if (obj.length !== length) { + $ERROR("Function's length property doesn't have specified value; expected " + + length + ", got " + obj.length + "."); + } + + var desc = Object.getOwnPropertyDescriptor(obj, "length"); + if (desc.writable) { + $ERROR("The length property of a built-in function must not be writable."); + } + if (desc.enumerable) { + $ERROR("The length property of a built-in function must not be enumerable."); + } + if (desc.configurable) { + $ERROR("The length property of a built-in function must not be configurable."); + } + } + + properties.forEach(function(prop) { + var desc = Object.getOwnPropertyDescriptor(obj, prop); + if (desc === undefined) { + $ERROR("Missing property " + prop + "."); + } + // accessor properties don't have writable attribute + if (desc.hasOwnProperty("writable") && !desc.writable) { + $ERROR("The " + prop + " property of this built-in function must be writable."); + } + if (desc.enumerable) { + $ERROR("The " + prop + " property of this built-in function must not be enumerable."); + } + if (!desc.configurable) { + $ERROR("The " + prop + " property of this built-in function must be configurable."); + } + }); + + // The remaining sections have been moved to the end of the test because + // unbound non-constructor functions written in JavaScript cannot possibly + // pass them, and we still want to test JavaScript implementations as much + // as possible. + + var exception; + if (isFunction && !isConstructor) { + // this is not a complete test for the presence of [[Construct]]: + // if it's absent, the exception must be thrown, but it may also + // be thrown if it's present and just has preconditions related to + // arguments or the this value that this statement doesn't meet. + try { + /*jshint newcap:false*/ + var instance = new obj(); + } catch (e) { + exception = e; + } + if (exception === undefined || exception.name !== "TypeError") { + $ERROR("Built-in functions that aren't constructors must throw TypeError when " + + "used in a \"new\" statement."); + } + } + + if (isFunction && !isConstructor && obj.hasOwnProperty("prototype")) { + $ERROR("Built-in functions that aren't constructors must not have a prototype property."); + } + + // passed the complete test! + return true; +} + diff --git a/js/src/tests/test402/lib/testIntl.js b/js/src/tests/test402/lib/testIntl.js new file mode 100644 index 000000000000..b009a2e9ed32 --- /dev/null +++ b/js/src/tests/test402/lib/testIntl.js @@ -0,0 +1,1167 @@ +// Copyright 2011-2012 Norbert Lindenberg. All rights reserved. +// Copyright 2012-2013 Mozilla Corporation. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/** + * This file contains shared functions for the tests in the conformance test + * suite for the ECMAScript Internationalization API. + * @author Norbert Lindenberg + */ + + +/** + * @description Calls the provided function for every service constructor in + * the Intl object, until f returns a falsy value. It returns the result of the + * last call to f, mapped to a boolean. + * @param {Function} f the function to call for each service constructor in + * the Intl object. + * @param {Function} Constructor the constructor object to test with. + * @result {Boolean} whether the test succeeded. + */ +function testWithIntlConstructors(f) { + var constructors = ["Collator", "NumberFormat", "DateTimeFormat"]; + return constructors.every(function (constructor) { + var Constructor = Intl[constructor]; + var result; + try { + result = f(Constructor); + } catch (e) { + e.message += " (Testing with " + constructor + ".)"; + throw e; + } + return result; + }); +} + + +/** + * Returns the name of the given constructor object, which must be one of + * Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat. + * @param {object} Constructor a constructor + * @return {string} the name of the constructor + */ +function getConstructorName(Constructor) { + switch (Constructor) { + case Intl.Collator: + return "Collator"; + case Intl.NumberFormat: + return "NumberFormat"; + case Intl.DateTimeFormat: + return "DateTimeFormat"; + default: + $ERROR("test internal error: unknown Constructor"); + } +} + + +/** + * Taints a named data property of the given object by installing + * a setter that throws an exception. + * @param {object} obj the object whose data property to taint + * @param {string} property the property to taint + */ +function taintDataProperty(obj, property) { + Object.defineProperty(obj, property, { + set: function(value) { + $ERROR("Client code can adversely affect behavior: setter for " + property + "."); + }, + enumerable: false, + configurable: true + }); +} + + +/** + * Taints a named method of the given object by replacing it with a function + * that throws an exception. + * @param {object} obj the object whose method to taint + * @param {string} property the name of the method to taint + */ +function taintMethod(obj, property) { + Object.defineProperty(obj, property, { + value: function() { + $ERROR("Client code can adversely affect behavior: method " + property + "."); + }, + writable: true, + enumerable: false, + configurable: true + }); +} + + +/** + * Taints the given properties (and similarly named properties) by installing + * setters on Object.prototype that throw exceptions. + * @param {Array} properties an array of property names to taint + */ +function taintProperties(properties) { + properties.forEach(function (property) { + var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"]; + adaptedProperties.forEach(function (property) { + taintDataProperty(Object.prototype, property); + }); + }); +} + + +/** + * Taints the Array object by creating a setter for the property "0" and + * replacing some key methods with functions that throw exceptions. + */ +function taintArray() { + taintDataProperty(Array.prototype, "0"); + taintMethod(Array.prototype, "indexOf"); + taintMethod(Array.prototype, "join"); + taintMethod(Array.prototype, "push"); + taintMethod(Array.prototype, "slice"); + taintMethod(Array.prototype, "sort"); +} + + +// auxiliary data for getLocaleSupportInfo +var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"]; +var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"]; +var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"]; +var localeSupportInfo = {}; + + +/** + * Gets locale support info for the given constructor object, which must be one + * of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat. + * @param {object} Constructor the constructor for which to get locale support info + * @return {object} locale support info with the following properties: + * supported: array of fully supported language tags + * byFallback: array of language tags that are supported through fallbacks + * unsupported: array of unsupported language tags + */ +function getLocaleSupportInfo(Constructor) { + var constructorName = getConstructorName(Constructor); + if (localeSupportInfo[constructorName] !== undefined) { + return localeSupportInfo[constructorName]; + } + + var allTags = []; + var i, j, k; + var language, script, country; + for (i = 0; i < languages.length; i++) { + language = languages[i]; + allTags.push(language); + for (j = 0; j < scripts.length; j++) { + script = scripts[j]; + allTags.push(language + "-" + script); + for (k = 0; k < countries.length; k++) { + country = countries[k]; + allTags.push(language + "-" + script + "-" + country); + } + } + for (k = 0; k < countries.length; k++) { + country = countries[k]; + allTags.push(language + "-" + country); + } + } + + var supported = []; + var byFallback = []; + var unsupported = []; + for (i = 0; i < allTags.length; i++) { + var request = allTags[i]; + var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale; + if (request === result) { + supported.push(request); + } else if (request.indexOf(result) === 0) { + byFallback.push(request); + } else { + unsupported.push(request); + } + } + + localeSupportInfo[constructorName] = { + supported: supported, + byFallback: byFallback, + unsupported: unsupported + }; + + return localeSupportInfo[constructorName]; +} + + +/** + * @description Tests whether locale is a String value representing a + * structurally valid and canonicalized BCP 47 language tag, as defined in + * sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API + * Specification. + * @param {String} locale the string to be tested. + * @result {Boolean} whether the test succeeded. + */ +function isCanonicalizedStructurallyValidLanguageTag(locale) { + + /** + * Regular expression defining BCP 47 language tags. + * + * Spec: RFC 5646 section 2.1. + */ + var alpha = "[a-zA-Z]", + digit = "[0-9]", + alphanum = "(" + alpha + "|" + digit + ")", + regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)", + irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)", + grandfathered = "(" + irregular + "|" + regular + ")", + privateuse = "(x(-[a-z0-9]{1,8})+)", + singleton = "(" + digit + "|[A-WY-Za-wy-z])", + extension = "(" + singleton + "(-" + alphanum + "{2,8})+)", + variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))", + region = "(" + alpha + "{2}|" + digit + "{3})", + script = "(" + alpha + "{4})", + extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})", + language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})", + langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?", + languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$", + languageTagRE = new RegExp(languageTag, "i"); + var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")", + duplicateSingletonRE = new RegExp(duplicateSingleton, "i"), + duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")", + duplicateVariantRE = new RegExp(duplicateVariant, "i"); + + + /** + * Verifies that the given string is a well-formed BCP 47 language tag + * with no duplicate variant or singleton subtags. + * + * Spec: ECMAScript Internationalization API Specification, draft, 6.2.2. + */ + function isStructurallyValidLanguageTag(locale) { + if (!languageTagRE.test(locale)) { + return false; + } + locale = locale.split(/-x-/)[0]; + return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale); + } + + + /** + * Mappings from complete tags to preferred values. + * + * Spec: IANA Language Subtag Registry. + */ + var __tagMappings = { + // property names must be in lower case; values in canonical form + + // grandfathered tags from IANA language subtag registry, file date 2011-08-25 + "art-lojban": "jbo", + "cel-gaulish": "cel-gaulish", + "en-gb-oed": "en-GB-oed", + "i-ami": "ami", + "i-bnn": "bnn", + "i-default": "i-default", + "i-enochian": "i-enochian", + "i-hak": "hak", + "i-klingon": "tlh", + "i-lux": "lb", + "i-mingo": "i-mingo", + "i-navajo": "nv", + "i-pwn": "pwn", + "i-tao": "tao", + "i-tay": "tay", + "i-tsu": "tsu", + "no-bok": "nb", + "no-nyn": "nn", + "sgn-be-fr": "sfb", + "sgn-be-nl": "vgt", + "sgn-ch-de": "sgg", + "zh-guoyu": "cmn", + "zh-hakka": "hak", + "zh-min": "zh-min", + "zh-min-nan": "nan", + "zh-xiang": "hsn", + // deprecated redundant tags from IANA language subtag registry, file date 2011-08-25 + "sgn-br": "bzs", + "sgn-co": "csn", + "sgn-de": "gsg", + "sgn-dk": "dsl", + "sgn-es": "ssp", + "sgn-fr": "fsl", + "sgn-gb": "bfi", + "sgn-gr": "gss", + "sgn-ie": "isg", + "sgn-it": "ise", + "sgn-jp": "jsl", + "sgn-mx": "mfs", + "sgn-ni": "ncs", + "sgn-nl": "dse", + "sgn-no": "nsl", + "sgn-pt": "psr", + "sgn-se": "swl", + "sgn-us": "ase", + "sgn-za": "sfs", + "zh-cmn": "cmn", + "zh-cmn-hans": "cmn-Hans", + "zh-cmn-hant": "cmn-Hant", + "zh-gan": "gan", + "zh-wuu": "wuu", + "zh-yue": "yue", + // deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25 + "ja-latn-hepburn-heploc": "ja-Latn-alalc97" + }; + + + /** + * Mappings from non-extlang subtags to preferred values. + * + * Spec: IANA Language Subtag Registry. + */ + var __subtagMappings = { + // property names and values must be in canonical case + // language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25 + "in": "id", + "iw": "he", + "ji": "yi", + "jw": "jv", + "mo": "ro", + "ayx": "nun", + "cjr": "mom", + "cmk": "xch", + "drh": "khk", + "drw": "prs", + "gav": "dev", + "mst": "mry", + "myt": "mry", + "tie": "ras", + "tkk": "twm", + "tnf": "prs", + // region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25 + "BU": "MM", + "DD": "DE", + "FX": "FR", + "TP": "TL", + "YD": "YE", + "ZR": "CD" + }; + + + /** + * Mappings from extlang subtags to preferred values. + * + * Spec: IANA Language Subtag Registry. + */ + var __extlangMappings = { + // extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25 + // values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed + "aao": ["aao", "ar"], + "abh": ["abh", "ar"], + "abv": ["abv", "ar"], + "acm": ["acm", "ar"], + "acq": ["acq", "ar"], + "acw": ["acw", "ar"], + "acx": ["acx", "ar"], + "acy": ["acy", "ar"], + "adf": ["adf", "ar"], + "ads": ["ads", "sgn"], + "aeb": ["aeb", "ar"], + "aec": ["aec", "ar"], + "aed": ["aed", "sgn"], + "aen": ["aen", "sgn"], + "afb": ["afb", "ar"], + "afg": ["afg", "sgn"], + "ajp": ["ajp", "ar"], + "apc": ["apc", "ar"], + "apd": ["apd", "ar"], + "arb": ["arb", "ar"], + "arq": ["arq", "ar"], + "ars": ["ars", "ar"], + "ary": ["ary", "ar"], + "arz": ["arz", "ar"], + "ase": ["ase", "sgn"], + "asf": ["asf", "sgn"], + "asp": ["asp", "sgn"], + "asq": ["asq", "sgn"], + "asw": ["asw", "sgn"], + "auz": ["auz", "ar"], + "avl": ["avl", "ar"], + "ayh": ["ayh", "ar"], + "ayl": ["ayl", "ar"], + "ayn": ["ayn", "ar"], + "ayp": ["ayp", "ar"], + "bbz": ["bbz", "ar"], + "bfi": ["bfi", "sgn"], + "bfk": ["bfk", "sgn"], + "bjn": ["bjn", "ms"], + "bog": ["bog", "sgn"], + "bqn": ["bqn", "sgn"], + "bqy": ["bqy", "sgn"], + "btj": ["btj", "ms"], + "bve": ["bve", "ms"], + "bvl": ["bvl", "sgn"], + "bvu": ["bvu", "ms"], + "bzs": ["bzs", "sgn"], + "cdo": ["cdo", "zh"], + "cds": ["cds", "sgn"], + "cjy": ["cjy", "zh"], + "cmn": ["cmn", "zh"], + "coa": ["coa", "ms"], + "cpx": ["cpx", "zh"], + "csc": ["csc", "sgn"], + "csd": ["csd", "sgn"], + "cse": ["cse", "sgn"], + "csf": ["csf", "sgn"], + "csg": ["csg", "sgn"], + "csl": ["csl", "sgn"], + "csn": ["csn", "sgn"], + "csq": ["csq", "sgn"], + "csr": ["csr", "sgn"], + "czh": ["czh", "zh"], + "czo": ["czo", "zh"], + "doq": ["doq", "sgn"], + "dse": ["dse", "sgn"], + "dsl": ["dsl", "sgn"], + "dup": ["dup", "ms"], + "ecs": ["ecs", "sgn"], + "esl": ["esl", "sgn"], + "esn": ["esn", "sgn"], + "eso": ["eso", "sgn"], + "eth": ["eth", "sgn"], + "fcs": ["fcs", "sgn"], + "fse": ["fse", "sgn"], + "fsl": ["fsl", "sgn"], + "fss": ["fss", "sgn"], + "gan": ["gan", "zh"], + "gom": ["gom", "kok"], + "gse": ["gse", "sgn"], + "gsg": ["gsg", "sgn"], + "gsm": ["gsm", "sgn"], + "gss": ["gss", "sgn"], + "gus": ["gus", "sgn"], + "hab": ["hab", "sgn"], + "haf": ["haf", "sgn"], + "hak": ["hak", "zh"], + "hds": ["hds", "sgn"], + "hji": ["hji", "ms"], + "hks": ["hks", "sgn"], + "hos": ["hos", "sgn"], + "hps": ["hps", "sgn"], + "hsh": ["hsh", "sgn"], + "hsl": ["hsl", "sgn"], + "hsn": ["hsn", "zh"], + "icl": ["icl", "sgn"], + "ils": ["ils", "sgn"], + "inl": ["inl", "sgn"], + "ins": ["ins", "sgn"], + "ise": ["ise", "sgn"], + "isg": ["isg", "sgn"], + "isr": ["isr", "sgn"], + "jak": ["jak", "ms"], + "jax": ["jax", "ms"], + "jcs": ["jcs", "sgn"], + "jhs": ["jhs", "sgn"], + "jls": ["jls", "sgn"], + "jos": ["jos", "sgn"], + "jsl": ["jsl", "sgn"], + "jus": ["jus", "sgn"], + "kgi": ["kgi", "sgn"], + "knn": ["knn", "kok"], + "kvb": ["kvb", "ms"], + "kvk": ["kvk", "sgn"], + "kvr": ["kvr", "ms"], + "kxd": ["kxd", "ms"], + "lbs": ["lbs", "sgn"], + "lce": ["lce", "ms"], + "lcf": ["lcf", "ms"], + "liw": ["liw", "ms"], + "lls": ["lls", "sgn"], + "lsg": ["lsg", "sgn"], + "lsl": ["lsl", "sgn"], + "lso": ["lso", "sgn"], + "lsp": ["lsp", "sgn"], + "lst": ["lst", "sgn"], + "lsy": ["lsy", "sgn"], + "ltg": ["ltg", "lv"], + "lvs": ["lvs", "lv"], + "lzh": ["lzh", "zh"], + "max": ["max", "ms"], + "mdl": ["mdl", "sgn"], + "meo": ["meo", "ms"], + "mfa": ["mfa", "ms"], + "mfb": ["mfb", "ms"], + "mfs": ["mfs", "sgn"], + "min": ["min", "ms"], + "mnp": ["mnp", "zh"], + "mqg": ["mqg", "ms"], + "mre": ["mre", "sgn"], + "msd": ["msd", "sgn"], + "msi": ["msi", "ms"], + "msr": ["msr", "sgn"], + "mui": ["mui", "ms"], + "mzc": ["mzc", "sgn"], + "mzg": ["mzg", "sgn"], + "mzy": ["mzy", "sgn"], + "nan": ["nan", "zh"], + "nbs": ["nbs", "sgn"], + "ncs": ["ncs", "sgn"], + "nsi": ["nsi", "sgn"], + "nsl": ["nsl", "sgn"], + "nsp": ["nsp", "sgn"], + "nsr": ["nsr", "sgn"], + "nzs": ["nzs", "sgn"], + "okl": ["okl", "sgn"], + "orn": ["orn", "ms"], + "ors": ["ors", "ms"], + "pel": ["pel", "ms"], + "pga": ["pga", "ar"], + "pks": ["pks", "sgn"], + "prl": ["prl", "sgn"], + "prz": ["prz", "sgn"], + "psc": ["psc", "sgn"], + "psd": ["psd", "sgn"], + "pse": ["pse", "ms"], + "psg": ["psg", "sgn"], + "psl": ["psl", "sgn"], + "pso": ["pso", "sgn"], + "psp": ["psp", "sgn"], + "psr": ["psr", "sgn"], + "pys": ["pys", "sgn"], + "rms": ["rms", "sgn"], + "rsi": ["rsi", "sgn"], + "rsl": ["rsl", "sgn"], + "sdl": ["sdl", "sgn"], + "sfb": ["sfb", "sgn"], + "sfs": ["sfs", "sgn"], + "sgg": ["sgg", "sgn"], + "sgx": ["sgx", "sgn"], + "shu": ["shu", "ar"], + "slf": ["slf", "sgn"], + "sls": ["sls", "sgn"], + "sqs": ["sqs", "sgn"], + "ssh": ["ssh", "ar"], + "ssp": ["ssp", "sgn"], + "ssr": ["ssr", "sgn"], + "svk": ["svk", "sgn"], + "swc": ["swc", "sw"], + "swh": ["swh", "sw"], + "swl": ["swl", "sgn"], + "syy": ["syy", "sgn"], + "tmw": ["tmw", "ms"], + "tse": ["tse", "sgn"], + "tsm": ["tsm", "sgn"], + "tsq": ["tsq", "sgn"], + "tss": ["tss", "sgn"], + "tsy": ["tsy", "sgn"], + "tza": ["tza", "sgn"], + "ugn": ["ugn", "sgn"], + "ugy": ["ugy", "sgn"], + "ukl": ["ukl", "sgn"], + "uks": ["uks", "sgn"], + "urk": ["urk", "ms"], + "uzn": ["uzn", "uz"], + "uzs": ["uzs", "uz"], + "vgt": ["vgt", "sgn"], + "vkk": ["vkk", "ms"], + "vkt": ["vkt", "ms"], + "vsi": ["vsi", "sgn"], + "vsl": ["vsl", "sgn"], + "vsv": ["vsv", "sgn"], + "wuu": ["wuu", "zh"], + "xki": ["xki", "sgn"], + "xml": ["xml", "sgn"], + "xmm": ["xmm", "ms"], + "xms": ["xms", "sgn"], + "yds": ["yds", "sgn"], + "ysl": ["ysl", "sgn"], + "yue": ["yue", "zh"], + "zib": ["zib", "sgn"], + "zlm": ["zlm", "ms"], + "zmi": ["zmi", "ms"], + "zsl": ["zsl", "sgn"], + "zsm": ["zsm", "ms"] + }; + + + /** + * Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags. + * + * Spec: ECMAScript Internationalization API Specification, draft, 6.2.3. + * Spec: RFC 5646, section 4.5. + */ + function canonicalizeLanguageTag(locale) { + + // start with lower case for easier processing, and because most subtags will need to be lower case anyway + locale = locale.toLowerCase(); + + // handle mappings for complete tags + if (__tagMappings.hasOwnProperty(locale)) { + return __tagMappings[locale]; + } + + var subtags = locale.split("-"); + var i = 0; + + // handle standard part: all subtags before first singleton or "x" + while (i < subtags.length) { + var subtag = subtags[i]; + if (subtag.length === 1 && (i > 0 || subtag === "x")) { + break; + } else if (i !== 0 && subtag.length === 2) { + subtag = subtag.toUpperCase(); + } else if (subtag.length === 4) { + subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase(); + } + if (__subtagMappings.hasOwnProperty(subtag)) { + subtag = __subtagMappings[subtag]; + } else if (__extlangMappings.hasOwnProperty(subtag)) { + subtag = __extlangMappings[subtag][0]; + if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) { + subtags.shift(); + i--; + } + } + subtags[i] = subtag; + i++; + } + var normal = subtags.slice(0, i).join("-"); + + // handle extensions + var extensions = []; + while (i < subtags.length && subtags[i] !== "x") { + var extensionStart = i; + i++; + while (i < subtags.length && subtags[i].length > 1) { + i++; + } + var extension = subtags.slice(extensionStart, i).join("-"); + extensions.push(extension); + } + extensions.sort(); + + // handle private use + var privateUse; + if (i < subtags.length) { + privateUse = subtags.slice(i).join("-"); + } + + // put everything back together + var canonical = normal; + if (extensions.length > 0) { + canonical += "-" + extensions.join("-"); + } + if (privateUse !== undefined) { + if (canonical.length > 0) { + canonical += "-" + privateUse; + } else { + canonical = privateUse; + } + } + + return canonical; + } + + return typeof locale === "string" && isStructurallyValidLanguageTag(locale) && + canonicalizeLanguageTag(locale) === locale; +} + + +/** + * Tests whether the named options property is correctly handled by the given constructor. + * @param {object} Constructor the constructor to test. + * @param {string} property the name of the options property to test. + * @param {string} type the type that values of the property are expected to have + * @param {Array} [values] an array of allowed values for the property. Not needed for boolean. + * @param {any} fallback the fallback value that the property assumes if not provided. + * @param {object} testOptions additional options: + * @param {boolean} isOptional whether support for this property is optional for implementations. + * @param {boolean} noReturn whether the resulting value of the property is not returned. + * @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent. + * @param {object} extra additional option to pass along, properties are value -> {option: value}. + * @return {boolean} whether the test succeeded. + */ +function testOption(Constructor, property, type, values, fallback, testOptions) { + var isOptional = testOptions !== undefined && testOptions.isOptional === true; + var noReturn = testOptions !== undefined && testOptions.noReturn === true; + var isILD = testOptions !== undefined && testOptions.isILD === true; + + function addExtraOptions(options, value, testOptions) { + if (testOptions !== undefined && testOptions.extra !== undefined) { + var extra; + if (value !== undefined && testOptions.extra[value] !== undefined) { + extra = testOptions.extra[value]; + } else if (testOptions.extra.any !== undefined) { + extra = testOptions.extra.any; + } + if (extra !== undefined) { + Object.getOwnPropertyNames(extra).forEach(function (prop) { + options[prop] = extra[prop]; + }); + } + } + } + + var testValues, options, obj, expected, actual, error; + + // test that the specified values are accepted. Also add values that convert to specified values. + if (type === "boolean") { + if (values === undefined) { + values = [true, false]; + } + testValues = values.slice(0); + testValues.push(888); + testValues.push(0); + } else if (type === "string") { + testValues = values.slice(0); + testValues.push({toString: function () { return values[0]; }}); + } + testValues.forEach(function (value) { + options = {}; + options[property] = value; + addExtraOptions(options, value, testOptions); + obj = new Constructor(undefined, options); + if (noReturn) { + if (obj.resolvedOptions().hasOwnProperty(property)) { + $ERROR("Option property " + property + " is returned, but shouldn't be."); + } + } else { + actual = obj.resolvedOptions()[property]; + if (isILD) { + if (actual !== undefined && values.indexOf(actual) === -1) { + $ERROR("Invalid value " + actual + " returned for property " + property + "."); + } + } else { + if (type === "boolean") { + expected = Boolean(value); + } else if (type === "string") { + expected = String(value); + } + if (actual !== expected && !(isOptional && actual === undefined)) { + $ERROR("Option value " + value + " for property " + property + + " was not accepted; got " + actual + " instead."); + } + } + } + }); + + // test that invalid values are rejected + if (type === "string") { + var invalidValues = ["invalidValue", -1, null]; + // assume that we won't have values in caseless scripts + if (values[0].toUpperCase() !== values[0]) { + invalidValues.push(values[0].toUpperCase()); + } else { + invalidValues.push(values[0].toLowerCase()); + } + invalidValues.forEach(function (value) { + options = {}; + options[property] = value; + addExtraOptions(options, value, testOptions); + error = undefined; + try { + obj = new Constructor(undefined, options); + } catch (e) { + error = e; + } + if (error === undefined) { + $ERROR("Invalid option value " + value + " for property " + property + " was not rejected."); + } else if (error.name !== "RangeError") { + $ERROR("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + "."); + } + }); + } + + // test that fallback value or another valid value is used if no options value is provided + if (!noReturn) { + options = {}; + addExtraOptions(options, undefined, testOptions); + obj = new Constructor(undefined, options); + actual = obj.resolvedOptions()[property]; + if (!(isOptional && actual === undefined)) { + if (fallback !== undefined) { + if (actual !== fallback) { + $ERROR("Option fallback value " + fallback + " for property " + property + + " was not used; got " + actual + " instead."); + } + } else { + if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) { + $ERROR("Invalid value " + actual + " returned for property " + property + "."); + } + } + } + } + + return true; +} + + +/** + * Tests whether the named property of the given object has a valid value + * and the default attributes of the properties of an object literal. + * @param {Object} obj the object to be tested. + * @param {string} property the name of the property + * @param {Function|Array} valid either a function that tests value for validity and returns a boolean, + * an array of valid values. + * @exception if the property has an invalid value. + */ +function testProperty(obj, property, valid) { + var desc = Object.getOwnPropertyDescriptor(obj, property); + if (!desc.writable) { + $ERROR("Property " + property + " must be writable."); + } + if (!desc.enumerable) { + $ERROR("Property " + property + " must be enumerable."); + } + if (!desc.configurable) { + $ERROR("Property " + property + " must be configurable."); + } + var value = desc.value; + var isValid = (typeof valid === "function") ? valid(value) : (valid.indexOf(value) !== -1); + if (!isValid) { + $ERROR("Property value " + value + " is not allowed for property " + property + "."); + } +} + + +/** + * Tests whether the named property of the given object, if present at all, has a valid value + * and the default attributes of the properties of an object literal. + * @param {Object} obj the object to be tested. + * @param {string} property the name of the property + * @param {Function|Array} valid either a function that tests value for validity and returns a boolean, + * an array of valid values. + * @exception if the property is present and has an invalid value. + */ +function mayHaveProperty(obj, property, valid) { + if (obj.hasOwnProperty(property)) { + testProperty(obj, property, valid); + } +} + + +/** + * Tests whether the given object has the named property with a valid value + * and the default attributes of the properties of an object literal. + * @param {Object} obj the object to be tested. + * @param {string} property the name of the property + * @param {Function|Array} valid either a function that tests value for validity and returns a boolean, + * an array of valid values. + * @exception if the property is missing or has an invalid value. + */ +function mustHaveProperty(obj, property, valid) { + if (!obj.hasOwnProperty(property)) { + $ERROR("Object is missing property " + property + "."); + } + testProperty(obj, property, valid); +} + + +/** + * Tests whether the given object does not have the named property. + * @param {Object} obj the object to be tested. + * @param {string} property the name of the property + * @exception if the property is present. + */ +function mustNotHaveProperty(obj, property) { + if (obj.hasOwnProperty(property)) { + $ERROR("Object has property it mustn't have: " + property + "."); + } +} + + +/** + * Properties of the RegExp constructor that may be affected by use of regular + * expressions, and the default values of these properties. Properties are from + * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties + */ +var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", + "$_", "$*", "$&", "$+", "$`", "$'", + "input", "lastMatch", "lastParen", "leftContext", "rightContext" +]; + +var regExpPropertiesDefaultValues = (function () { + var values = Object.create(null); + regExpProperties.forEach(function (property) { + values[property] = RegExp[property]; + }); + return values; +}()); + + +/** + * Tests that executing the provided function (which may use regular expressions + * in its implementation) does not create or modify unwanted properties on the + * RegExp constructor. + */ +function testForUnwantedRegExpChanges(testFunc) { + regExpProperties.forEach(function (property) { + RegExp[property] = regExpPropertiesDefaultValues[property]; + }); + testFunc(); + regExpProperties.forEach(function (property) { + if (RegExp[property] !== regExpPropertiesDefaultValues[property]) { + $ERROR("RegExp has unexpected property " + property + " with value " + + RegExp[property] + "."); + } + }); +} + + +/** + * Tests whether name is a valid BCP 47 numbering system name + * and not excluded from use in the ECMAScript Internationalization API. + * @param {string} name the name to be tested. + * @return {boolean} whether name is a valid BCP 47 numbering system name and + * allowed for use in the ECMAScript Internationalization API. + */ + +function isValidNumberingSystem(name) { + + // source: CLDR file common/bcp47/number.xml; version CLDR 21. + var numberingSystems = [ + "arab", + "arabext", + "armn", + "armnlow", + "bali", + "beng", + "brah", + "cakm", + "cham", + "deva", + "ethi", + "finance", + "fullwide", + "geor", + "grek", + "greklow", + "gujr", + "guru", + "hanidec", + "hans", + "hansfin", + "hant", + "hantfin", + "hebr", + "java", + "jpan", + "jpanfin", + "kali", + "khmr", + "knda", + "osma", + "lana", + "lanatham", + "laoo", + "latn", + "lepc", + "limb", + "mlym", + "mong", + "mtei", + "mymr", + "mymrshan", + "native", + "nkoo", + "olck", + "orya", + "roman", + "romanlow", + "saur", + "shrd", + "sora", + "sund", + "talu", + "takr", + "taml", + "tamldec", + "telu", + "thai", + "tibt", + "traditio", + "vaii" + ]; + + var excluded = [ + "finance", + "native", + "traditio" + ]; + + + return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1; +} + + +/** + * Provides the digits of numbering systems with simple digit mappings, + * as specified in 11.3.2. + */ + +var numberingSystemDigits = { + arab: "٠١٢٣٤٥٦٧٨٩", + arabext: "۰۱۲۳۴۵۶۷۸۹", + beng: "০১২৩৪৫৬৭৮৯", + deva: "०१२३४५६७८९", + fullwide: "0123456789", + gujr: "૦૧૨૩૪૫૬૭૮૯", + guru: "੦੧੨੩੪੫੬੭੮੯", + hanidec: "〇一二三四五六七八九", + khmr: "០១២៣៤៥៦៧៨៩", + knda: "೦೧೨೩೪೫೬೭೮೯", + laoo: "໐໑໒໓໔໕໖໗໘໙", + latn: "0123456789", + mlym: "൦൧൨൩൪൫൬൭൮൯", + mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙", + mymr: "၀၁၂၃၄၅၆၇၈၉", + orya: "୦୧୨୩୪୫୬୭୮୯", + tamldec: "௦௧௨௩௪௫௬௭௮௯", + telu: "౦౧౨౩౪౫౬౭౮౯", + thai: "๐๑๒๓๔๕๖๗๘๙", + tibt: "༠༡༢༣༤༥༦༧༨༩" +}; + + +/** + * Tests that number formatting is handled correctly. The function checks that the + * digit sequences in formatted output are as specified, converted to the + * selected numbering system, and embedded in consistent localized patterns. + * @param {Array} locales the locales to be tested. + * @param {Array} numberingSystems the numbering systems to be tested. + * @param {Object} options the options to pass to Intl.NumberFormat. Options + * must include {useGrouping: false}, and must cause 1.1 to be formatted + * pre- and post-decimal digits. + * @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings + * in unlocalized format with Western digits. + */ + +function testNumberFormat(locales, numberingSystems, options, testData) { + locales.forEach(function (locale) { + numberingSystems.forEach(function (numbering) { + var digits = numberingSystemDigits[numbering]; + var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options); + + function getPatternParts(positive) { + var n = positive ? 1.1 : -1.1; + var formatted = format.format(n); + var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)"; + var match = formatted.match(new RegExp(oneoneRE)); + if (match === null) { + $ERROR("Unexpected formatted " + n + " for " + + format.resolvedOptions().locale + " and options " + + JSON.stringify(options) + ": " + formatted); + } + return match; + } + + function toNumbering(raw) { + return raw.replace(/[0-9]/g, function (digit) { + return digits[digit.charCodeAt(0) - "0".charCodeAt(0)]; + }); + } + + function buildExpected(raw, patternParts) { + var period = raw.indexOf("."); + if (period === -1) { + return patternParts[1] + toNumbering(raw) + patternParts[3]; + } else { + return patternParts[1] + + toNumbering(raw.substring(0, period)) + + patternParts[2] + + toNumbering(raw.substring(period + 1)) + + patternParts[3]; + } + } + + if (format.resolvedOptions().numberingSystem === numbering) { + // figure out prefixes, infixes, suffixes for positive and negative values + var posPatternParts = getPatternParts(true); + var negPatternParts = getPatternParts(false); + + Object.getOwnPropertyNames(testData).forEach(function (input) { + var rawExpected = testData[input]; + var patternParts; + if (rawExpected[0] === "-") { + patternParts = negPatternParts; + rawExpected = rawExpected.substring(1); + } else { + patternParts = posPatternParts; + } + var expected = buildExpected(rawExpected, patternParts); + var actual = format.format(input); + if (actual !== expected) { + $ERROR("Formatted value for " + input + ", " + + format.resolvedOptions().locale + " and options " + + JSON.stringify(options) + " is " + actual + "; expected " + expected + "."); + } + }); + } + }); + }); +} + + +/** + * Return the components of date-time formats. + * @return {Array} an array with all date-time components. + */ + +function getDateTimeComponents() { + return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"]; +} + + +/** + * Return the valid values for the given date-time component, as specified + * by the table in section 12.1.1. + * @param {string} component a date-time component. + * @return {Array} an array with the valid values for the component. + */ + +function getDateTimeComponentValues(component) { + + var components = { + weekday: ["narrow", "short", "long"], + era: ["narrow", "short", "long"], + year: ["2-digit", "numeric"], + month: ["2-digit", "numeric", "narrow", "short", "long"], + day: ["2-digit", "numeric"], + hour: ["2-digit", "numeric"], + minute: ["2-digit", "numeric"], + second: ["2-digit", "numeric"], + timeZoneName: ["short", "long"] + }; + + var result = components[component]; + if (result === undefined) { + $ERROR("Internal error: No values defined for date-time component " + component + "."); + } + return result; +} + + +/** + * Tests that the given value is valid for the given date-time component. + * @param {string} component a date-time component. + * @param {string} value the value to be tested. + * @return {boolean} true if the test succeeds. + * @exception if the test fails. + */ + +function testValidDateTimeComponentValue(component, value) { + if (getDateTimeComponentValues(component).indexOf(value) === -1) { + $ERROR("Invalid value " + value + " for date-time component " + component + "."); + } + return true; +} + + +/** + * Verifies that the actual array matches the expected one in length, elements, + * and element order. + * @param {Array} expected the expected array. + * @param {Array} actual the actual array. + * @return {boolean} true if the test succeeds. + * @exception if the test fails. + */ +function testArraysAreSame(expected, actual) { + for (i = 0; i < Math.max(actual.length, expected.length); i++) { + if (actual[i] !== expected[i]) { + $ERROR("Result array element at index " + i + " should be \"" + + expected[i] + "\" but is \"" + actual[i] + "\"."); + } + } + return true; +} + diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index f53e0d639d31..9e77cf3e6da1 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -210,7 +210,7 @@ ArgumentsObject::createUnexpected(JSContext *cx, AbstractFramePtr frame) } static JSBool -args_delProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) +args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded) { ArgumentsObject &argsobj = obj->asArguments(); if (JSID_IS_INT(id)) { @@ -222,6 +222,7 @@ args_delProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValu } else if (JSID_IS_ATOM(id, cx->names().callee)) { argsobj.asNormalArguments().clearCallee(); } + *succeeded = true; return true; } @@ -289,8 +290,8 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHa * of setting it in case the user has changed the prototype to an object * that has a setter for this id. */ - RootedValue value(cx); - return baseops::DeleteGeneric(cx, obj, id, &value, false) && + JSBool succeeded; + return baseops::DeleteGeneric(cx, obj, id, &succeeded) && baseops::DefineGeneric(cx, obj, id, vp, NULL, NULL, attrs); } @@ -408,8 +409,8 @@ StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Mut * args_delProperty to clear the corresponding reserved slot so the GC can * collect its value. */ - RootedValue value(cx); - return baseops::DeleteGeneric(cx, argsobj, id, &value, strict) && + JSBool succeeded; + return baseops::DeleteGeneric(cx, argsobj, id, &succeeded) && baseops::DefineGeneric(cx, argsobj, id, vp, NULL, NULL, attrs); } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 1f822c2d3141..032867ff5841 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -1659,7 +1659,7 @@ Class Debugger::jsclass = { "Debugger", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Debugger::finalize, NULL, /* checkAccess */ NULL, /* call */ @@ -2696,7 +2696,7 @@ Class DebuggerScript_class = { "Script", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, NULL, /* checkAccess */ NULL, /* call */ @@ -3497,7 +3497,7 @@ DebuggerFrame_finalize(FreeOp *fop, RawObject obj) Class DebuggerFrame_class = { "Frame", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, DebuggerFrame_finalize }; @@ -3642,7 +3642,7 @@ DebuggerFrame_getOlder(JSContext *cx, unsigned argc, Value *vp) Class DebuggerArguments_class = { "Arguments", JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGARGUMENTS_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; @@ -4093,7 +4093,7 @@ Class DebuggerObject_class = { "Object", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGOBJECT_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, NULL, /* checkAccess */ NULL, /* call */ @@ -4542,8 +4542,12 @@ DebuggerObject_deleteProperty(JSContext *cx, unsigned argc, Value *vp) if (!cx->compartment->wrap(cx, &nameArg)) return false; + JSBool succeeded; ErrorCopier ec(ac, dbg->toJSObject()); - return JSObject::deleteByValue(cx, obj, nameArg, args.rval(), false); + if (!JSObject::deleteByValue(cx, obj, nameArg, &succeeded)) + return false; + args.rval().setBoolean(succeeded); + return true; } enum SealHelperOp { Seal, Freeze, PreventExtensions }; @@ -4881,7 +4885,7 @@ Class DebuggerEnv_class = { "Environment", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGENV_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, NULL, /* checkAccess */ NULL, /* call */ diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index b6716c25683e..97e2300eebf4 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -576,7 +576,7 @@ GlobalDebuggees_finalize(FreeOp *fop, RawObject obj) static Class GlobalDebuggees_class = { "GlobalDebuggee", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, GlobalDebuggees_finalize }; diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index e5dc014b5ba6..b2fe90262352 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -209,7 +209,7 @@ Class js::RegExpClass = { JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, /* enumerate */ diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp index ff4b46b514b8..8f2b761fcaec 100644 --- a/js/src/vm/RegExpStatics.cpp +++ b/js/src/vm/RegExpStatics.cpp @@ -41,7 +41,7 @@ Class js::RegExpStaticsClass = { "RegExpStatics", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index d101aaf222c4..91025f40cbcf 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -260,7 +260,7 @@ JS_PUBLIC_DATA(Class) js::CallClass = { "Call", JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -273,7 +273,7 @@ Class js::DeclEnvClass = { JSCLASS_HAS_RESERVED_SLOTS(DeclEnvObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -516,26 +516,26 @@ with_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, static JSBool with_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, - MutableHandleValue rval, JSBool strict) + JSBool *succeeded) { RootedObject actual(cx, &obj->asWith().object()); - return JSObject::deleteProperty(cx, actual, name, rval, strict); + return JSObject::deleteProperty(cx, actual, name, succeeded); } static JSBool with_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index, - MutableHandleValue rval, JSBool strict) + JSBool *succeeded) { RootedObject actual(cx, &obj->asWith().object()); - return JSObject::deleteElement(cx, actual, index, rval, strict); + return JSObject::deleteElement(cx, actual, index, succeeded); } static JSBool with_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, - MutableHandleValue rval, JSBool strict) + JSBool *succeeded) { RootedObject actual(cx, &obj->asWith().object()); - return JSObject::deleteSpecial(cx, actual, sid, rval, strict); + return JSObject::deleteSpecial(cx, actual, sid, succeeded); } static JSBool @@ -557,7 +557,7 @@ Class js::WithClass = { JSCLASS_HAS_RESERVED_SLOTS(WithObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, @@ -715,7 +715,7 @@ Class js::BlockClass = { JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, JS_PropertyStub, /* addProperty */ - JS_PropertyStub, /* delProperty */ + JS_DeletePropertyStub, /* delProperty */ JS_PropertyStub, /* getProperty */ JS_StrictPropertyStub, /* setProperty */ JS_EnumerateStub, diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a6aa8f4f0212..0fed32c33a84 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -38,7 +38,7 @@ selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep static JSClass self_hosting_global_class = { "self-hosting-global", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL diff --git a/js/xpconnect/idl/nsIXPCScriptable.idl b/js/xpconnect/idl/nsIXPCScriptable.idl index 569f3ff42082..4315e4dacdcb 100644 --- a/js/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/xpconnect/idl/nsIXPCScriptable.idl @@ -19,7 +19,7 @@ * boolean to PR_TRUE before making the call. Implementations may skip writing * to *_retval unless they want to return PR_FALSE. */ -[uuid(1236e34a-21e0-423c-a8c8-9b3f1e6d7060)] +[uuid(33b9d098-e680-4e4c-88a2-57cccceac145)] interface nsIXPCScriptable : nsISupports { /* bitflags used for 'flags' (only 32 bits available!) */ @@ -84,8 +84,7 @@ interface nsIXPCScriptable : nsISupports in JSValPtr vp); boolean delProperty(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsid id, - in JSValPtr vp); + in JSContextPtr cx, in JSObjectPtr obj, in jsid id); // The returnCode should be set to NS_SUCCESS_I_DID_SOMETHING if // this method does something. diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index ae12a414638a..1532b39c8f8a 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -81,7 +81,7 @@ static JSClass kFakeBackstagePassJSClass = "FakeBackstagePass", 0, JS_PropertyStub, - JS_PropertyStub, + JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, diff --git a/js/xpconnect/public/xpc_map_end.h b/js/xpconnect/public/xpc_map_end.h index 70c40454cb16..d101c87ceafe 100644 --- a/js/xpconnect/public/xpc_map_end.h +++ b/js/xpconnect/public/xpc_map_end.h @@ -113,7 +113,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::AddProperty(nsIXPConnectWrappedNative *wrapper, #endif #ifndef XPC_MAP_WANT_DELPROPERTY -NS_IMETHODIMP XPC_MAP_CLASSNAME::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, bool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, bool *_retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp index 767156623aa8..79492ef16c4e 100644 --- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -848,7 +848,7 @@ static JSFunctionSpec glob_functions[] = { JSClass global_class = { "global", 0, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr }; @@ -969,7 +969,7 @@ env_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, static JSClass env_class = { "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, env_setProperty, env_enumerate, (JSResolveOp) env_resolve, JS_ConvertStub, nullptr diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 3253644d1b70..0bb740a91e91 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -34,6 +34,7 @@ #include "nsJSEnvironment.h" #include "nsXMLHttpRequest.h" #include "mozilla/Telemetry.h" +#include "mozilla/XPTInterfaceInfoManager.h" #include "nsDOMClassInfoID.h" using namespace mozilla; @@ -120,7 +121,7 @@ public: virtual ~nsXPCComponents_Interfaces(); private: - nsCOMPtr mManager; + nsCOMArray mInterfaces; }; /* void getInterfaces (out uint32_t count, [array, size_is (count), retval] @@ -215,9 +216,9 @@ nsXPCComponents_Interfaces::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) return NS_ERROR_NOT_AVAILABLE; } -nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() : - mManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)) +nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() { + XPTInterfaceInfoManager::GetSingleton()->GetScriptableInterfaces(mInterfaces); } nsXPCComponents_Interfaces::~nsXPCComponents_Interfaces() @@ -254,64 +255,36 @@ nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative *wrapper, uint32_t enum_op, jsval * statep, jsid * idp, bool *_retval) { - nsIEnumerator* e; - switch (enum_op) { case JSENUMERATE_INIT: case JSENUMERATE_INIT_ALL: { - if (!mManager || - NS_FAILED(mManager->EnumerateInterfaces(&e)) || !e || - NS_FAILED(e->First())) - - { - *statep = JSVAL_NULL; - return NS_ERROR_UNEXPECTED; - } - - *statep = PRIVATE_TO_JSVAL(e); + *statep = JSVAL_ZERO; if (idp) - *idp = INT_TO_JSID(0); // indicate that we don't know the count + *idp = INT_TO_JSID(mInterfaces.Length()); return NS_OK; } case JSENUMERATE_NEXT: { - nsCOMPtr isup; + uint32_t idx = JSVAL_TO_INT(*statep); + nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(idx); + *statep = UINT_TO_JSVAL(idx + 1); - e = (nsIEnumerator*) JSVAL_TO_PRIVATE(*statep); + if (interface) { + JSString* idstr; + const char* name; - while (1) { - if (static_cast(NS_ENUMERATOR_FALSE) == e->IsDone() && - NS_SUCCEEDED(e->CurrentItem(getter_AddRefs(isup))) && isup) { - e->Next(); - nsCOMPtr iface(do_QueryInterface(isup)); - if (iface) { - JSString* idstr; - const char* name; - bool scriptable; - - if (NS_SUCCEEDED(iface->IsScriptable(&scriptable)) && - !scriptable) { - continue; - } - - if (NS_SUCCEEDED(iface->GetNameShared(&name)) && name && - nullptr != (idstr = JS_NewStringCopyZ(cx, name)) && - JS_ValueToId(cx, STRING_TO_JSVAL(idstr), idp)) { - return NS_OK; - } - } + if (NS_SUCCEEDED(interface->GetNameShared(&name)) && name && + nullptr != (idstr = JS_NewStringCopyZ(cx, name)) && + JS_ValueToId(cx, STRING_TO_JSVAL(idstr), idp)) { + return NS_OK; } - // else... - break; } - // FALL THROUGH + // fall through } case JSENUMERATE_DESTROY: default: - e = (nsIEnumerator*) JSVAL_TO_PRIVATE(*statep); - NS_IF_RELEASE(e); *statep = JSVAL_NULL; return NS_OK; } @@ -326,17 +299,16 @@ nsXPCComponents_Interfaces::NewResolve(nsIXPConnectWrappedNative *wrapper, { RootedObject obj(cx, objArg); RootedId id(cx, idArg); - - if (!mManager || !JSID_IS_STRING(id)) - return NS_OK; - JSAutoByteString name; RootedString str(cx, JSID_TO_STRING(id)); - // we only allow interfaces by name here - if (name.encodeLatin1(cx, JSID_TO_STRING(id)) && name.ptr()[0] != '{') { + if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id)) && + name.ptr()[0] != '{') + { + // we only allow interfaces by name here nsCOMPtr info; - mManager->GetInfoForName(name.ptr(), getter_AddRefs(info)); + XPTInterfaceInfoManager::GetSingleton()-> + GetInfoForName(name.ptr(), getter_AddRefs(info)); if (!info) return NS_OK; @@ -428,7 +400,7 @@ public: virtual ~nsXPCComponents_InterfacesByID(); private: - nsCOMPtr mManager; + nsCOMArray mInterfaces; }; /***************************************************************************/ @@ -524,9 +496,9 @@ nsXPCComponents_InterfacesByID::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) return NS_ERROR_NOT_AVAILABLE; } -nsXPCComponents_InterfacesByID::nsXPCComponents_InterfacesByID() : - mManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)) +nsXPCComponents_InterfacesByID::nsXPCComponents_InterfacesByID() { + XPTInterfaceInfoManager::GetSingleton()->GetScriptableInterfaces(mInterfaces); } nsXPCComponents_InterfacesByID::~nsXPCComponents_InterfacesByID() @@ -561,68 +533,38 @@ nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative *wrapper, uint32_t enum_op, jsval * statep, jsid * idp, bool *_retval) { - nsIEnumerator* e; - switch (enum_op) { case JSENUMERATE_INIT: case JSENUMERATE_INIT_ALL: { - if (!mManager || - NS_FAILED(mManager->EnumerateInterfaces(&e)) || !e || - NS_FAILED(e->First())) - - { - *statep = JSVAL_NULL; - return NS_ERROR_UNEXPECTED; - } - - *statep = PRIVATE_TO_JSVAL(e); + *statep = JSVAL_ZERO; if (idp) - *idp = INT_TO_JSID(0); // indicate that we don't know the count + *idp = INT_TO_JSID(mInterfaces.Length()); return NS_OK; } case JSENUMERATE_NEXT: { - nsCOMPtr isup; + uint32_t idx = JSVAL_TO_INT(*statep); + nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(idx); + *statep = UINT_TO_JSVAL(idx + 1); + if (interface) { + nsIID const *iid; + char idstr[NSID_LENGTH]; + JSString* jsstr; - e = (nsIEnumerator*) JSVAL_TO_PRIVATE(*statep); - - while (1) { - if (static_cast(NS_ENUMERATOR_FALSE) == e->IsDone() && - NS_SUCCEEDED(e->CurrentItem(getter_AddRefs(isup))) && isup) { - e->Next(); - nsCOMPtr iface(do_QueryInterface(isup)); - if (iface) { - nsIID const *iid; - char idstr[NSID_LENGTH]; - JSString* jsstr; - bool scriptable; - - if (NS_SUCCEEDED(iface->IsScriptable(&scriptable)) && - !scriptable) { - continue; - } - - if (NS_SUCCEEDED(iface->GetIIDShared(&iid))) { - iid->ToProvidedString(idstr); - jsstr = JS_NewStringCopyZ(cx, idstr); - if (jsstr && - JS_ValueToId(cx, STRING_TO_JSVAL(jsstr), idp)) { - return NS_OK; - } - } + if (NS_SUCCEEDED(interface->GetIIDShared(&iid))) { + iid->ToProvidedString(idstr); + jsstr = JS_NewStringCopyZ(cx, idstr); + if (jsstr && JS_ValueToId(cx, STRING_TO_JSVAL(jsstr), idp)) { + return NS_OK; } } - // else... - break; } // FALL THROUGH } case JSENUMERATE_DESTROY: default: - e = (nsIEnumerator*) JSVAL_TO_PRIVATE(*statep); - NS_IF_RELEASE(e); *statep = JSVAL_NULL; return NS_OK; } @@ -639,9 +581,6 @@ nsXPCComponents_InterfacesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, RootedId id(cx, idArg); RootedString str(cx, JSID_TO_STRING(id)); - if (!mManager || !JSID_IS_STRING(id)) - return NS_OK; - if (38 != JS_GetStringLength(str)) return NS_OK; @@ -651,7 +590,8 @@ nsXPCComponents_InterfacesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, return NS_OK; nsCOMPtr info; - mManager->GetInfoForIID(&iid, getter_AddRefs(info)); + XPTInterfaceInfoManager::GetSingleton()-> + GetInfoForIID(&iid, getter_AddRefs(info)); if (!info) return NS_OK; @@ -3052,7 +2992,7 @@ sandbox_convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleV static JSClass SandboxClass = { "Sandbox", XPCONNECT_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, sandbox_enumerate, sandbox_resolve, sandbox_convert, sandbox_finalize, NULL, NULL, NULL, NULL, TraceXPCGlobal }; diff --git a/js/xpconnect/src/XPCJSContextStack.cpp b/js/xpconnect/src/XPCJSContextStack.cpp index cab07993ba79..f1d09ba659da 100644 --- a/js/xpconnect/src/XPCJSContextStack.cpp +++ b/js/xpconnect/src/XPCJSContextStack.cpp @@ -134,7 +134,7 @@ SafeFinalize(JSFreeOp *fop, JSObject* obj) static JSClass global_class = { "global_for_XPCJSContextStack_SafeJSContext", XPCONNECT_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize, NULL, NULL, NULL, NULL, TraceXPCGlobal }; diff --git a/js/xpconnect/src/XPCJSMemoryReporter.h b/js/xpconnect/src/XPCJSMemoryReporter.h index fe507c5eacb2..ac95b7813035 100644 --- a/js/xpconnect/src/XPCJSMemoryReporter.h +++ b/js/xpconnect/src/XPCJSMemoryReporter.h @@ -26,8 +26,6 @@ public: WindowPaths *topWindowPaths, nsIMemoryMultiReporterCallback *cb, nsISupports *closure); - - static nsresult GetExplicitNonHeap(int64_t *n); }; } diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index a9a83b7a6da6..9632d264b81a 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2150,14 +2150,6 @@ class JSCompartmentsMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter return NS_OK; } - - NS_IMETHOD - GetExplicitNonHeap(int64_t *n) - { - // This reporter does neither "explicit" nor NONHEAP measurements. - *n = 0; - return NS_OK; - } }; NS_IMPL_THREADSAFE_ISUPPORTS1(JSCompartmentsMultiReporter @@ -2425,14 +2417,6 @@ JSMemoryMultiReporter::CollectReports(WindowPaths *windowPaths, return NS_OK; } -nsresult -JSMemoryMultiReporter::GetExplicitNonHeap(int64_t *n) -{ - JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime(); - *reinterpret_cast(n) = JS::GetExplicitNonHeapForRuntime(rt, JsMallocSizeOf); - return NS_OK; -} - } // namespace xpc #ifdef MOZ_CRASHREPORTER diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index d734d27a73dd..8432193d51e2 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -94,7 +94,7 @@ PointerFinalize(JSFreeOp *fop, JSObject *obj) JSClass PointerHolderClass = { "Pointer", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PointerFinalize }; diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 35125019ffeb..de781293e608 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -498,6 +498,13 @@ XPC_WN_CannotModifyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); } +static JSBool +XPC_WN_CantDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, + JSBool *succeeded) +{ + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); +} + static JSBool XPC_WN_CannotModifyStrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp) @@ -759,7 +766,7 @@ XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { /* Mandatory non-null function pointer members. */ XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty - XPC_WN_CannotModifyPropertyStub, // delProperty + XPC_WN_CantDeletePropertyStub, // delProperty JS_PropertyStub, // getProperty XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty @@ -843,6 +850,21 @@ XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHan return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp); } +static JSBool +XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded) +{ + MORPH_SLIM_WRAPPER(cx, obj); + XPCCallContext ccx(JS_CALLER, cx, obj); + XPCWrappedNative* wrapper = ccx.GetWrapper(); + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); + + if (ccx.GetResolvingWrapper() == wrapper) { + *succeeded = true; + return true; + } + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); +} + // macro fun! #define PRE_HELPER_STUB_NO_SLIM \ XPCWrappedNative* wrapper = \ @@ -891,10 +913,10 @@ XPC_WN_Helper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, static JSBool XPC_WN_Helper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSMutableHandleValue vp) + JSBool *succeeded) { PRE_HELPER_STUB - DelProperty(wrapper, cx, obj, id, vp.address(), &retval); + DelProperty(wrapper, cx, obj, id, &retval); POST_HELPER_STUB } @@ -1311,15 +1333,15 @@ XPCNativeScriptableShared::PopulateJSClass() addProperty = XPC_WN_CannotModifyPropertyStub; mJSClass.base.addProperty = addProperty; - JSPropertyOp delProperty; + JSDeletePropertyOp delProperty; if (mFlags.WantDelProperty()) delProperty = XPC_WN_Helper_DelProperty; else if (mFlags.UseJSStubForDelProperty()) - delProperty = JS_PropertyStub; + delProperty = JS_DeletePropertyStub; else if (mFlags.AllowPropModsDuringResolve()) - delProperty = XPC_WN_MaybeResolvingPropertyStub; + delProperty = XPC_WN_MaybeResolvingDeletePropertyStub; else - delProperty = XPC_WN_CannotModifyPropertyStub; + delProperty = XPC_WN_CantDeletePropertyStub; mJSClass.base.delProperty = delProperty; if (mFlags.WantGetProperty()) @@ -1610,7 +1632,7 @@ js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = { /* Mandatory non-null function pointer members. */ JS_PropertyStub, // addProperty; - JS_PropertyStub, // delProperty; + JS_DeletePropertyStub, // delProperty; JS_PropertyStub, // getProperty; JS_StrictPropertyStub, // setProperty; XPC_WN_Shared_Proto_Enumerate, // enumerate; @@ -1635,7 +1657,7 @@ js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = { /* Mandatory non-null function pointer members. */ JS_PropertyStub, // addProperty; - JS_PropertyStub, // delProperty; + JS_DeletePropertyStub, // delProperty; JS_PropertyStub, // getProperty; JS_StrictPropertyStub, // setProperty; XPC_WN_Shared_Proto_Enumerate, // enumerate; @@ -1724,7 +1746,7 @@ js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = { /* Mandatory non-null function pointer members. */ XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; - XPC_WN_CannotModifyPropertyStub, // delProperty; + XPC_WN_CantDeletePropertyStub, // delProperty; JS_PropertyStub, // getProperty; XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty; XPC_WN_Shared_Proto_Enumerate, // enumerate; @@ -1749,7 +1771,7 @@ js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { /* Mandatory non-null function pointer members. */ XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; - XPC_WN_CannotModifyPropertyStub, // delProperty; + XPC_WN_CantDeletePropertyStub, // delProperty; JS_PropertyStub, // getProperty; XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty; XPC_WN_Shared_Proto_Enumerate, // enumerate; @@ -1830,7 +1852,7 @@ js::Class XPC_WN_Tearoff_JSClass = { WRAPPER_SLOTS, // flags; XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty; - XPC_WN_CannotModifyPropertyStub, // delProperty; + XPC_WN_CantDeletePropertyStub, // delProperty; JS_PropertyStub, // getProperty; XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty; XPC_WN_TearOff_Enumerate, // enumerate; diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index 488b8a4eace3..9593accc82da 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -301,7 +301,7 @@ js::Class XPC_WN_NoHelper_Proto_JSClass = { /* Mandatory non-null function pointer members. */ JS_PropertyStub, // addProperty; - JS_PropertyStub, // delProperty; + JS_DeletePropertyStub, // delProperty; JS_PropertyStub, // getProperty; JS_StrictPropertyStub, // setProperty; JS_EnumerateStub, // enumerate; diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 84136594fc6e..e8e9ee71e9b3 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -40,7 +40,9 @@ #include "nsDOMMutationObserver.h" #include "nsICycleCollectorListener.h" #include "nsThread.h" +#include "mozilla/XPTInterfaceInfoManager.h" +using namespace mozilla; using namespace mozilla::dom; using namespace xpc; using namespace JS; @@ -76,7 +78,6 @@ const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1"; nsXPConnect::nsXPConnect() : mRuntime(nullptr), - mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)), mDefaultSecurityManager(nullptr), mDefaultSecurityManagerFlags(0), mShuttingDown(false), @@ -150,9 +151,6 @@ nsXPConnect::GetXPConnect() if (!gSelf->mRuntime) { NS_RUNTIMEABORT("Couldn't create XPCJSRuntime."); } - if (!gSelf->mInterfaceInfoManager) { - NS_RUNTIMEABORT("Couldn't get global interface info manager."); - } // Initial extra ref to keep the singleton alive // balanced by explicit call to ReleaseXPConnectSingleton() @@ -223,19 +221,6 @@ nsXPConnect::ReleaseXPConnectSingleton() } } -// static -nsresult -nsXPConnect::GetInterfaceInfoManager(nsIInterfaceInfoSuperManager** iim, - nsXPConnect* xpc /*= nullptr*/) -{ - if (!xpc && !(xpc = GetXPConnect())) - return NS_ERROR_FAILURE; - - *iim = xpc->mInterfaceInfoManager; - NS_IF_ADDREF(*iim); - return NS_OK; -} - // static XPCJSRuntime* nsXPConnect::GetRuntimeInstance() @@ -257,61 +242,17 @@ nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info) /***************************************************************************/ -typedef bool (*InfoTester)(nsIInterfaceInfoManager* manager, const void* data, - nsIInterfaceInfo** info); - -static bool IIDTester(nsIInterfaceInfoManager* manager, const void* data, - nsIInterfaceInfo** info) -{ - return NS_SUCCEEDED(manager->GetInfoForIID((const nsIID *) data, info)) && - *info; -} - -static bool NameTester(nsIInterfaceInfoManager* manager, const void* data, - nsIInterfaceInfo** info) -{ - return NS_SUCCEEDED(manager->GetInfoForName((const char *) data, info)) && - *info; -} - -static nsresult FindInfo(InfoTester tester, const void* data, - nsIInterfaceInfoSuperManager* iism, - nsIInterfaceInfo** info) -{ - if (tester(iism, data, info)) - return NS_OK; - - // If not found, then let's ask additional managers. - - bool yes; - nsCOMPtr list; - - if (NS_SUCCEEDED(iism->HasAdditionalManagers(&yes)) && yes && - NS_SUCCEEDED(iism->EnumerateAdditionalManagers(getter_AddRefs(list))) && - list) { - bool more; - nsCOMPtr current; - - while (NS_SUCCEEDED(list->HasMoreElements(&more)) && more && - NS_SUCCEEDED(list->GetNext(getter_AddRefs(current))) && current) { - if (tester(current, data, info)) - return NS_OK; - } - } - - return NS_ERROR_NO_INTERFACE; -} - nsresult nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info) { - return FindInfo(IIDTester, aIID, mInterfaceInfoManager, info); + return XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(aIID, info); } nsresult nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info) { - return FindInfo(NameTester, name, mInterfaceInfoManager, info); + nsresult rv = XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, info); + return NS_FAILED(rv) ? NS_OK : NS_ERROR_NO_INTERFACE; } bool @@ -1771,7 +1712,6 @@ nsXPConnect::DebugDump(int16_t depth) XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead)); XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager)); XPC_LOG_ALWAYS(("mDefaultSecurityManagerFlags of %x", mDefaultSecurityManagerFlags)); - XPC_LOG_ALWAYS(("mInterfaceInfoManager @ %x", mInterfaceInfoManager.get())); if (mRuntime) { if (depth) mRuntime->DebugDump(depth); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 78f86b4acce2..bcc2d5532602 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -119,7 +119,6 @@ #include "nsMemory.h" #include "nsIXPConnect.h" #include "nsIInterfaceInfo.h" -#include "nsIInterfaceInfoManager.h" #include "nsIXPCScriptable.h" #include "nsIXPCSecurityManager.h" #include "nsIJSRuntimeService.h" @@ -491,10 +490,6 @@ public: void AssertNoObjectsToTrace(void* aPossibleJSHolder); #endif - // Gets addref'd pointer - static nsresult GetInterfaceInfoManager(nsIInterfaceInfoSuperManager** iim, - nsXPConnect* xpc = nullptr); - static JSBool IsISupportsDescendant(nsIInterfaceInfo* info); nsIXPCSecurityManager* GetDefaultSecurityManager() const @@ -568,7 +563,6 @@ private: static JSBool gOnceAliveNowDead; XPCJSRuntime* mRuntime; - nsCOMPtr mInterfaceInfoManager; nsIXPCSecurityManager* mDefaultSecurityManager; uint16_t mDefaultSecurityManagerFlags; JSBool mShuttingDown; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index b3e6098e1fbf..d76dc37f9a68 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -42,7 +42,7 @@ namespace XrayUtils { JSClass HolderClass = { "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(2), - JS_PropertyStub, JS_PropertyStub, holder_get, holder_set, + JS_PropertyStub, JS_DeletePropertyStub, holder_get, holder_set, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; } @@ -320,7 +320,7 @@ ExpandoObjectFinalize(JSFreeOp *fop, JSObject *obj) JSClass ExpandoObjectClass = { "XrayExpandoObject", JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ExpandoObjectFinalize }; diff --git a/layout/reftests/svg/paint-order-02-ref.svg b/layout/reftests/svg/paint-order-02-ref.svg index a0c3bb4f560e..46731a5bff77 100644 --- a/layout/reftests/svg/paint-order-02-ref.svg +++ b/layout/reftests/svg/paint-order-02-ref.svg @@ -4,25 +4,33 @@ --> Reference for paint-order-02.svg - + - - - + + + - - + + + - - + + + - - + + - - + + - hello there - hello there + + + + + + + hello there + hello there diff --git a/layout/reftests/svg/paint-order-02.svg b/layout/reftests/svg/paint-order-02.svg index aad9d694d397..52e7ac2dd91e 100644 --- a/layout/reftests/svg/paint-order-02.svg +++ b/layout/reftests/svg/paint-order-02.svg @@ -4,9 +4,17 @@ --> Test that the paint-order property works - + - + + + + + + + + + diff --git a/mozglue/android/nsGeckoUtils.cpp b/mozglue/android/nsGeckoUtils.cpp index fa21db6933f3..0a5e327a76e7 100644 --- a/mozglue/android/nsGeckoUtils.cpp +++ b/mozglue/android/nsGeckoUtils.cpp @@ -5,12 +5,6 @@ #include -#ifdef MOZ_MEMORY -// Wrap malloc and free to use jemalloc -#define malloc __wrap_malloc -#define free __wrap_free -#endif - #include #include #include "APKOpen.h" diff --git a/mozglue/build/BionicGlue.cpp b/mozglue/build/BionicGlue.cpp index a9f6c5d07c72..46ca2c3d6b66 100644 --- a/mozglue/build/BionicGlue.cpp +++ b/mozglue/build/BionicGlue.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -20,7 +21,44 @@ struct AtForkFuncs { void (*parent)(void); void (*child)(void); }; -static std::vector atfork; + +/* jemalloc's initialization calls pthread_atfork. When pthread_atfork (see + * further below) stores the corresponding data, it's going to allocate memory, + * which will loop back to jemalloc's initialization, leading to a dead-lock. + * So, for that specific vector, we use a special allocator that returns a + * static buffer for small sizes, and force the initial vector capacity to + * a size enough to store one atfork function table. */ +template +struct SpecialAllocator: public std::allocator +{ + SpecialAllocator(): bufUsed(false) {} + + inline typename std::allocator::pointer allocate(typename std::allocator::size_type n, const void * = 0) { + if (!bufUsed && n == 1) { + bufUsed = true; + return buf.addr(); + } + return reinterpret_cast(::operator new(sizeof(T) * n)); + } + + inline void deallocate(typename std::allocator::pointer p, typename std::allocator::size_type n) { + if (p == buf.addr()) + bufUsed = false; + else + ::operator delete(p); + } + + template + struct rebind { + typedef SpecialAllocator other; + }; + +private: + mozilla::AlignedStorage2 buf; + bool bufUsed; +}; + +static std::vector > atfork; #ifdef MOZ_WIDGET_GONK #include "cpuacct.h" @@ -46,6 +84,8 @@ WRAP(pthread_atfork)(void (*prepare)(void), void (*parent)(void), void (*child)( funcs.prepare = prepare; funcs.parent = parent; funcs.child = child; + if (!atfork.capacity()) + atfork.reserve(1); atfork.push_back(funcs); return 0; } @@ -133,40 +173,77 @@ PR_GetEnvLock(void) #ifndef MOZ_WIDGET_GONK #include -extern "C" NS_EXPORT void* __wrap_memccpy(void * a0, const void * a1, int a2, size_t a3) { return memccpy(a0, a1, a2, a3); } -extern "C" NS_EXPORT void* __wrap_memchr(const void * a0, int a1, size_t a2) { return memchr(a0, a1, a2); } -extern "C" NS_EXPORT void* __wrap_memrchr(const void * a0, int a1, size_t a2) { return memrchr(a0, a1, a2); } -extern "C" NS_EXPORT int __wrap_memcmp(const void * a0, const void * a1, size_t a2) { return memcmp(a0, a1, a2); } -extern "C" NS_EXPORT void* __wrap_memcpy(void * a0, const void * a1, size_t a2) { return memcpy(a0, a1, a2); } -extern "C" NS_EXPORT void* __wrap_memmove(void * a0, const void * a1, size_t a2) { return memmove(a0, a1, a2); } -extern "C" NS_EXPORT void* __wrap_memset(void * a0, int a1, size_t a2) { return memset(a0, a1, a2); } -extern "C" NS_EXPORT void* __wrap_memmem(const void * a0, size_t a1, const void * a2, size_t a3) { return memmem(a0, a1, a2, a3); } -extern "C" NS_EXPORT void __wrap_memswap(void * a0, void * a1, size_t a2) { memswap(a0, a1, a2); } -extern "C" NS_EXPORT char* __wrap_index(const char * a0, int a1) { return index(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strchr(const char * a0, int a1) { return strchr(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strrchr(const char * a0, int a1) { return strrchr(a0, a1); } -extern "C" NS_EXPORT size_t __wrap_strlen(const char * a0) { return strlen(a0); } -extern "C" NS_EXPORT int __wrap_strcmp(const char * a0, const char * a1) { return strcmp(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strcpy(char * a0, const char * a1) { return strcpy(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strcat(char * a0, const char * a1) { return strcat(a0, a1); } -extern "C" NS_EXPORT int __wrap_strcasecmp(const char * a0, const char * a1) { return strcasecmp(a0, a1); } -extern "C" NS_EXPORT int __wrap_strncasecmp(const char * a0, const char * a1, size_t a2) { return strncasecmp(a0, a1, a2); } -extern "C" NS_EXPORT char* __wrap_strstr(const char * a0, const char * a1) { return strstr(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strcasestr(const char * a0, const char * a1) { return strcasestr(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strtok(char * a0, const char * a1) { return strtok(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strtok_r(char * a0, const char * a1, char** a2) { return strtok_r(a0, a1, a2); } -extern "C" NS_EXPORT char* __wrap_strerror(int a0) { return strerror(a0); } -extern "C" NS_EXPORT int __wrap_strerror_r(int a0, char * a1, size_t a2) { return strerror_r(a0, a1, a2); } -extern "C" NS_EXPORT size_t __wrap_strnlen(const char * a0, size_t a1) { return strnlen(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strncat(char * a0, const char * a1, size_t a2) { return strncat(a0, a1, a2); } -extern "C" NS_EXPORT int __wrap_strncmp(const char * a0, const char * a1, size_t a2) { return strncmp(a0, a1, a2); } -extern "C" NS_EXPORT char* __wrap_strncpy(char * a0, const char * a1, size_t a2) { return strncpy(a0, a1, a2); } -extern "C" NS_EXPORT size_t __wrap_strlcat(char * a0, const char * a1, size_t a2) { return strlcat(a0, a1, a2); } -extern "C" NS_EXPORT size_t __wrap_strlcpy(char * a0, const char * a1, size_t a2) { return strlcpy(a0, a1, a2); } -extern "C" NS_EXPORT size_t __wrap_strcspn(const char * a0, const char * a1) { return strcspn(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strpbrk(const char * a0, const char * a1) { return strpbrk(a0, a1); } -extern "C" NS_EXPORT char* __wrap_strsep(char ** a0, const char * a1) { return strsep(a0, a1); } -extern "C" NS_EXPORT size_t __wrap_strspn(const char * a0, const char * a1) { return strspn(a0, a1); } -extern "C" NS_EXPORT int __wrap_strcoll(const char * a0, const char * a1) { return strcoll(a0, a1); } -extern "C" NS_EXPORT size_t __wrap_strxfrm(char * a0, const char * a1, size_t a2) { return strxfrm(a0, a1, a2); } +extern "C" NS_EXPORT void* __real_memccpy(void * a0, const void * a1, int a2, size_t a3); +extern "C" NS_EXPORT void* __real_memchr(const void * a0, int a1, size_t a2); +extern "C" NS_EXPORT void* __real_memrchr(const void * a0, int a1, size_t a2); +extern "C" NS_EXPORT int __real_memcmp(const void * a0, const void * a1, size_t a2); +extern "C" NS_EXPORT void* __real_memcpy(void * a0, const void * a1, size_t a2); +extern "C" NS_EXPORT void* __real_memmove(void * a0, const void * a1, size_t a2); +extern "C" NS_EXPORT void* __real_memset(void * a0, int a1, size_t a2); +extern "C" NS_EXPORT void* __real_memmem(const void * a0, size_t a1, const void * a2, size_t a3); +extern "C" NS_EXPORT void __real_memswap(void * a0, void * a1, size_t a2); +extern "C" NS_EXPORT char* __real_index(const char * a0, int a1); +extern "C" NS_EXPORT char* __real_strchr(const char * a0, int a1); +extern "C" NS_EXPORT char* __real_strrchr(const char * a0, int a1); +extern "C" NS_EXPORT size_t __real_strlen(const char * a0); +extern "C" NS_EXPORT int __real_strcmp(const char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strcpy(char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strcat(char * a0, const char * a1); +extern "C" NS_EXPORT int __real_strcasecmp(const char * a0, const char * a1); +extern "C" NS_EXPORT int __real_strncasecmp(const char * a0, const char * a1, size_t a2); +extern "C" NS_EXPORT char* __real_strstr(const char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strcasestr(const char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strtok(char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strtok_r(char * a0, const char * a1, char** a2); +extern "C" NS_EXPORT char* __real_strerror(int a0); +extern "C" NS_EXPORT int __real_strerror_r(int a0, char * a1, size_t a2); +extern "C" NS_EXPORT size_t __real_strnlen(const char * a0, size_t a1); +extern "C" NS_EXPORT char* __real_strncat(char * a0, const char * a1, size_t a2); +extern "C" NS_EXPORT int __real_strncmp(const char * a0, const char * a1, size_t a2); +extern "C" NS_EXPORT char* __real_strncpy(char * a0, const char * a1, size_t a2); +extern "C" NS_EXPORT size_t __real_strlcat(char * a0, const char * a1, size_t a2); +extern "C" NS_EXPORT size_t __real_strlcpy(char * a0, const char * a1, size_t a2); +extern "C" NS_EXPORT size_t __real_strcspn(const char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strpbrk(const char * a0, const char * a1); +extern "C" NS_EXPORT char* __real_strsep(char ** a0, const char * a1); +extern "C" NS_EXPORT size_t __real_strspn(const char * a0, const char * a1); +extern "C" NS_EXPORT int __real_strcoll(const char * a0, const char * a1); +extern "C" NS_EXPORT size_t __real_strxfrm(char * a0, const char * a1, size_t a2); + +extern "C" NS_EXPORT void* __wrap_memccpy(void * a0, const void * a1, int a2, size_t a3) { return __real_memccpy(a0, a1, a2, a3); } +extern "C" NS_EXPORT void* __wrap_memchr(const void * a0, int a1, size_t a2) { return __real_memchr(a0, a1, a2); } +extern "C" NS_EXPORT void* __wrap_memrchr(const void * a0, int a1, size_t a2) { return __real_memrchr(a0, a1, a2); } +extern "C" NS_EXPORT int __wrap_memcmp(const void * a0, const void * a1, size_t a2) { return __real_memcmp(a0, a1, a2); } +extern "C" NS_EXPORT void* __wrap_memcpy(void * a0, const void * a1, size_t a2) { return __real_memcpy(a0, a1, a2); } +extern "C" NS_EXPORT void* __wrap_memmove(void * a0, const void * a1, size_t a2) { return __real_memmove(a0, a1, a2); } +extern "C" NS_EXPORT void* __wrap_memset(void * a0, int a1, size_t a2) { return __real_memset(a0, a1, a2); } +extern "C" NS_EXPORT void* __wrap_memmem(const void * a0, size_t a1, const void * a2, size_t a3) { return __real_memmem(a0, a1, a2, a3); } +extern "C" NS_EXPORT void __wrap_memswap(void * a0, void * a1, size_t a2) { __real_memswap(a0, a1, a2); } +extern "C" NS_EXPORT char* __wrap_index(const char * a0, int a1) { return __real_index(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strchr(const char * a0, int a1) { return __real_strchr(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strrchr(const char * a0, int a1) { return __real_strrchr(a0, a1); } +extern "C" NS_EXPORT size_t __wrap_strlen(const char * a0) { return __real_strlen(a0); } +extern "C" NS_EXPORT int __wrap_strcmp(const char * a0, const char * a1) { return __real_strcmp(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strcpy(char * a0, const char * a1) { return __real_strcpy(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strcat(char * a0, const char * a1) { return __real_strcat(a0, a1); } +extern "C" NS_EXPORT int __wrap_strcasecmp(const char * a0, const char * a1) { return __real_strcasecmp(a0, a1); } +extern "C" NS_EXPORT int __wrap_strncasecmp(const char * a0, const char * a1, size_t a2) { return __real_strncasecmp(a0, a1, a2); } +extern "C" NS_EXPORT char* __wrap_strstr(const char * a0, const char * a1) { return __real_strstr(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strcasestr(const char * a0, const char * a1) { return __real_strcasestr(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strtok(char * a0, const char * a1) { return __real_strtok(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strtok_r(char * a0, const char * a1, char** a2) { return __real_strtok_r(a0, a1, a2); } +extern "C" NS_EXPORT char* __wrap_strerror(int a0) { return __real_strerror(a0); } +extern "C" NS_EXPORT int __wrap_strerror_r(int a0, char * a1, size_t a2) { return __real_strerror_r(a0, a1, a2); } +extern "C" NS_EXPORT size_t __wrap_strnlen(const char * a0, size_t a1) { return __real_strnlen(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strncat(char * a0, const char * a1, size_t a2) { return __real_strncat(a0, a1, a2); } +extern "C" NS_EXPORT int __wrap_strncmp(const char * a0, const char * a1, size_t a2) { return __real_strncmp(a0, a1, a2); } +extern "C" NS_EXPORT char* __wrap_strncpy(char * a0, const char * a1, size_t a2) { return __real_strncpy(a0, a1, a2); } +extern "C" NS_EXPORT size_t __wrap_strlcat(char * a0, const char * a1, size_t a2) { return __real_strlcat(a0, a1, a2); } +extern "C" NS_EXPORT size_t __wrap_strlcpy(char * a0, const char * a1, size_t a2) { return __real_strlcpy(a0, a1, a2); } +extern "C" NS_EXPORT size_t __wrap_strcspn(const char * a0, const char * a1) { return __real_strcspn(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strpbrk(const char * a0, const char * a1) { return __real_strpbrk(a0, a1); } +extern "C" NS_EXPORT char* __wrap_strsep(char ** a0, const char * a1) { return __real_strsep(a0, a1); } +extern "C" NS_EXPORT size_t __wrap_strspn(const char * a0, const char * a1) { return __real_strspn(a0, a1); } +extern "C" NS_EXPORT int __wrap_strcoll(const char * a0, const char * a1) { return __real_strcoll(a0, a1); } +extern "C" NS_EXPORT size_t __wrap_strxfrm(char * a0, const char * a1, size_t a2) { return __real_strxfrm(a0, a1, a2); } #endif diff --git a/mozglue/build/Makefile.in b/mozglue/build/Makefile.in index ace0153e737b..ddd085dac57b 100644 --- a/mozglue/build/Makefile.in +++ b/mozglue/build/Makefile.in @@ -115,7 +115,7 @@ endif SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,mfbt,$(DEPTH)/mfbt) ifeq (Android, $(OS_TARGET)) -WRAP_LDFLAGS = +WRAP_LDFLAGS := $(filter -Wl%,$(WRAP_LDFLAGS)) endif include $(topsrcdir)/config/rules.mk diff --git a/netwerk/base/src/ProxyAutoConfig.cpp b/netwerk/base/src/ProxyAutoConfig.cpp index 5727b39a8891..dec6ca456149 100644 --- a/netwerk/base/src/ProxyAutoConfig.cpp +++ b/netwerk/base/src/ProxyAutoConfig.cpp @@ -549,7 +549,7 @@ private: JSClass JSRuntimeWrapper::sGlobalClass = { "PACResolutionThreadGlobal", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; diff --git a/security/manager/ssl/src/CertVerifier.cpp b/security/manager/ssl/src/CertVerifier.cpp new file mode 100644 index 000000000000..6b021a8e01d7 --- /dev/null +++ b/security/manager/ssl/src/CertVerifier.cpp @@ -0,0 +1,416 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CertVerifier.h" +#include "nsNSSComponent.h" +#include "cert.h" +#include "secerr.h" + + +#ifdef PR_LOGGING +extern PRLogModuleInfo* gPIPNSSLog; +#endif + +namespace mozilla { namespace psm { + +extern SECStatus getFirstEVPolicy(CERTCertificate *cert, SECOidTag &outOidTag); +extern CERTCertList* getRootsForOid(SECOidTag oid_tag); + +const CertVerifier::Flags CertVerifier::FLAG_LOCAL_ONLY = 1; + +CertVerifier::CertVerifier(missing_cert_download_config mcdc, + crl_download_config cdc, + ocsp_download_config odc, + ocsp_strict_config osc, + any_revo_fresh_config arfc, + const char *firstNetworkRevocationMethod) + : mMissingCertDownloadEnabled(mcdc == missing_cert_download_on) + , mCRLDownloadEnabled(cdc == crl_download_allowed) + , mOCSPDownloadEnabled(odc == ocsp_on) + , mOCSPStrict(osc == ocsp_strict) + , mRequireRevocationInfo(arfc == any_revo_strict) + , mCRLFirst(firstNetworkRevocationMethod != nullptr && + !strcmp("crl", firstNetworkRevocationMethod)) +{ + MOZ_COUNT_CTOR(CertVerifier); +} + +CertVerifier::~CertVerifier() +{ + MOZ_COUNT_DTOR(CertVerifier); +} + + +static SECStatus +ClassicVerifyCert(CERTCertificate * cert, + const SECCertificateUsage usage, + const PRTime time, + nsIInterfaceRequestor * pinArg, + /*optional out*/ CERTCertList **validationChain, + /*optional out*/ CERTVerifyLog *verifyLog) +{ + SECStatus rv; + SECCertUsage enumUsage; + if (validationChain) { + switch(usage){ + case certificateUsageSSLClient: + enumUsage = certUsageSSLClient; + break; + case certificateUsageSSLServer: + enumUsage = certUsageSSLServer; + break; + case certificateUsageSSLServerWithStepUp: + enumUsage = certUsageSSLServerWithStepUp; + break; + case certificateUsageSSLCA: + enumUsage = certUsageSSLCA; + break; + case certificateUsageEmailSigner: + enumUsage = certUsageEmailSigner; + break; + case certificateUsageEmailRecipient: + enumUsage = certUsageEmailRecipient; + break; + case certificateUsageObjectSigner: + enumUsage = certUsageObjectSigner; + break; + case certificateUsageUserCertImport: + enumUsage = certUsageUserCertImport; + break; + case certificateUsageVerifyCA: + enumUsage = certUsageVerifyCA; + break; + case certificateUsageProtectedObjectSigner: + enumUsage = certUsageProtectedObjectSigner; + break; + case certificateUsageStatusResponder: + enumUsage = certUsageStatusResponder; + break; + case certificateUsageAnyCA: + enumUsage = certUsageAnyCA; + break; + default: + return SECFailure; + } + } + if (usage == certificateUsageSSLServer) { + /* SSL server cert verification has always used CERT_VerifyCert, so we + * continue to use it for SSL cert verification to minimize the risk of + * there being any differnce in results between CERT_VerifyCert and + * CERT_VerifyCertificate. + */ + rv = CERT_VerifyCert(CERT_GetDefaultCertDB(), cert, true, + certUsageSSLServer, time, pinArg, verifyLog); + } else { + rv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), cert, true, + usage, time, pinArg, + verifyLog, nullptr); + } + if (rv == SECSuccess && validationChain) { + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: getting chain in 'classic' \n")); + *validationChain = CERT_GetCertChainFromCert(cert, time, enumUsage); + if (!*validationChain) { + rv = SECFailure; + } + } + return rv; +} + +SECStatus +CertVerifier::VerifyCert(CERTCertificate * cert, + const SECCertificateUsage usage, + const PRTime time, + nsIInterfaceRequestor * pinArg, + const Flags flags, + /*optional out*/ CERTCertList **validationChain, + /*optional out*/ SECOidTag *evOidPolicy, + /*optional out*/ CERTVerifyLog *verifyLog) +{ + if (!cert) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (validationChain) { + *validationChain = nullptr; + } + if (evOidPolicy) { + *evOidPolicy = SEC_OID_UNKNOWN; + } + + ScopedCERTCertList trustAnchors; + SECStatus rv; + SECOidTag evPolicy = SEC_OID_UNKNOWN; + + // Do EV checking only for sslserver usage + if (usage == certificateUsageSSLServer) { + SECStatus srv = getFirstEVPolicy(cert, evPolicy); + if (srv == SECSuccess) { + if (evPolicy != SEC_OID_UNKNOWN) { + trustAnchors = getRootsForOid(evPolicy); + } + if (!trustAnchors) { + return SECFailure; + } + } else { + // Do not setup EV verification params + evPolicy = SEC_OID_UNKNOWN; + } + } + + MOZ_ASSERT_IF(evPolicy != SEC_OID_UNKNOWN, trustAnchors); + + size_t i = 0; + size_t validationChainLocation = 0; + size_t validationTrustAnchorLocation = 0; + CERTValOutParam cvout[4]; + if (verifyLog) { + cvout[i].type = cert_po_errorLog; + cvout[i].value.pointer.log = verifyLog; + ++i; + } + if (validationChain) { + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: setting up validation chain outparam.\n")); + validationChainLocation = i; + cvout[i].type = cert_po_certList; + cvout[i].value.pointer.cert = nullptr; + ++i; + validationTrustAnchorLocation = i; + cvout[i].type = cert_po_trustAnchor; + cvout[i].value.pointer.chain = nullptr; + ++i; + } + cvout[i].type = cert_po_end; + + CERTRevocationFlags rev; + + CERTRevocationMethodIndex revPreferredMethods[2]; + rev.leafTests.preferred_methods = + rev.chainTests.preferred_methods = revPreferredMethods; + + uint64_t revFlagsPerMethod[2]; + rev.leafTests.cert_rev_flags_per_method = + rev.chainTests.cert_rev_flags_per_method = revFlagsPerMethod; + rev.leafTests.number_of_preferred_methods = + rev.chainTests.number_of_preferred_methods = 1; + + rev.leafTests.number_of_defined_methods = + rev.chainTests.number_of_defined_methods = cert_revocation_method_ocsp + 1; + + const bool localOnly = flags & FLAG_LOCAL_ONLY; + CERTValInParam cvin[6]; + + // Parameters for both EV and DV validation + cvin[0].type = cert_pi_useAIACertFetch; + cvin[0].value.scalar.b = mMissingCertDownloadEnabled && !localOnly; + cvin[1].type = cert_pi_revocationFlags; + cvin[1].value.pointer.revocation = &rev; + cvin[2].type = cert_pi_date; + cvin[2].value.scalar.time = time; + i = 3; + const size_t evParamLocation = i; + + // Declare dv variables here so that we can use they dont cross the goto line! + // after classic is gone, we can move the declaration below (and remove the + // goto) + bool strictRevocation; + + if (evPolicy != SEC_OID_UNKNOWN) { + // EV setup! + // This flags are not quite correct, but it is what we have now, so keeping + // them identical for bug landing purposes. Should be fixed later! + uint64_t revMethodFlags = + CERT_REV_M_TEST_USING_THIS_METHOD + | (mOCSPDownloadEnabled ? CERT_REV_M_ALLOW_NETWORK_FETCHING + : CERT_REV_M_FORBID_NETWORK_FETCHING) + | CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE + | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE + | CERT_REV_M_IGNORE_MISSING_FRESH_INFO + | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO; + + rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] = + rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] = revMethodFlags; + rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = + rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = revMethodFlags; + + rev.leafTests.cert_rev_method_independent_flags = + rev.chainTests.cert_rev_method_independent_flags = + // avoiding the network is good, let's try local first + CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST + // is overall revocation requirement strict or relaxed? + | CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE + ; + + rev.leafTests.preferred_methods[0] = + rev.chainTests.preferred_methods[0] = cert_revocation_method_ocsp; + + cvin[i].type = cert_pi_policyOID; + cvin[i].value.arraySize = 1; + cvin[i].value.array.oids = &evPolicy; + ++i; + MOZ_ASSERT(trustAnchors); + cvin[i].type = cert_pi_trustAnchors; + cvin[i].value.pointer.chain = trustAnchors; + ++i; + + cvin[i].type = cert_pi_end; + + rv = CERT_PKIXVerifyCert(cert, usage, cvin, cvout, pinArg); + if (rv == SECSuccess) { + if (evOidPolicy) { + *evOidPolicy = evPolicy; + } + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, + ("VerifyCert: successful CERT_PKIXVerifyCert(ev) \n")); + goto pkix_done; + } + + if (validationChain && *validationChain) { + // There SHOULD not be a validation chain on failure, asserion here for + // the debug builds AND a fallback for production builds + MOZ_ASSERT(false, + "certPKIXVerifyCert returned failure AND a validationChain"); + CERT_DestroyCertList(*validationChain); + *validationChain = nullptr; + } + + if (verifyLog) { + // Cleanup the log so that it is ready the the next validation + CERTVerifyLogNode *i_node; + for (i_node = verifyLog->head; i_node; i_node = i_node->next) { + //destroy cert if any. + if (i_node->cert) { + CERT_DestroyCertificate(i_node->cert); + } + // No need to cleanup the actual nodes in the arena. + } + verifyLog->count = 0; + verifyLog->head = nullptr; + verifyLog->tail = nullptr; + } + + } + + if (!nsNSSComponent::globalConstFlagUsePKIXVerification){ + // XXX: we do not care about the localOnly flag (currently) as the + // caller that wants localOnly should disable and reenable the fetching. + return ClassicVerifyCert(cert, usage, time, pinArg, validationChain, + verifyLog); + } + + // The current flags check the chain the same way as the leafs + rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] = + rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] = + // implicit default source - makes no sense for CRLs + CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE + + // let's not stop on fresh CRL. If OCSP is enabled, too, let's check it + | CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO + + // no fresh CRL? well, let other flag decide whether to fail or not + | CERT_REV_M_IGNORE_MISSING_FRESH_INFO + + // testing using local CRLs is always allowed + | CERT_REV_M_TEST_USING_THIS_METHOD + + // no local crl and don't know where to get it from? ignore + | CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE + + // crl download based on parameter + | ((mCRLDownloadEnabled && !localOnly) ? + CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING) + ; + + rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = + rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] = + // use OCSP + CERT_REV_M_TEST_USING_THIS_METHOD + + // if app has a default OCSP responder configured, let's use it + | CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE + + // of course OCSP doesn't work without a source. let's accept such certs + | CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE + + // if ocsp is required stop on lack of freshness + | (mOCSPStrict ? + CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO : CERT_REV_M_IGNORE_MISSING_FRESH_INFO) + + // ocsp success is sufficient + | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO + + // ocsp enabled controls network fetching, too + | ((mOCSPDownloadEnabled && !localOnly) ? + CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING) + ; + + rev.leafTests.preferred_methods[0] = + rev.chainTests.preferred_methods[0] = + mCRLFirst ? cert_revocation_method_crl : cert_revocation_method_ocsp; + + rev.leafTests.cert_rev_method_independent_flags = + rev.chainTests.cert_rev_method_independent_flags = + // avoiding the network is good, let's try local first + CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST + + // is overall revocation requirement strict or relaxed? + | (mRequireRevocationInfo ? + CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE : CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT) + ; + + // Skip EV parameters + cvin[evParamLocation].type = cert_pi_end; + + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: calling CERT_PKIXVerifyCert(dv) \n")); + rv = CERT_PKIXVerifyCert(cert, usage, cvin, cvout, pinArg); + +pkix_done: + if (validationChain) { + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: validation chain requested\n")); + ScopedCERTCertificate trustAnchor(cvout[validationTrustAnchorLocation].value.pointer.cert); + + if (rv == SECSuccess) { + if (! cvout[validationChainLocation].value.pointer.chain) { + return SECFailure; + } + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: I have a chain\n")); + *validationChain = cvout[validationChainLocation].value.pointer.chain; + if (trustAnchor) { + // we should only add the issuer to the chain if it is not already + // present. On CA cert checking, the issuer is the same cert, so in + // that case we do not add the cert to the chain. + if (!CERT_CompareCerts(trustAnchor, cert)) { + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: adding issuer to tail for display\n")); + // note: rv is reused to catch errors on cert creation! + rv = CERT_AddCertToListTail(*validationChain, + CERT_DupCertificate(trustAnchor)); + if (rv != SECSuccess) { + CERT_DestroyCertList(*validationChain); + *validationChain = nullptr; + } + } + } + } else { + // Validation was a fail, clean up if needed + if (cvout[validationChainLocation].value.pointer.chain) { + CERT_DestroyCertList(cvout[validationChainLocation].value.pointer.chain); + } + } + } + return rv; +} + +TemporaryRef +GetDefaultCertVerifier() +{ + static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); + + nsCOMPtr nssComponent(do_GetService(kNSSComponentCID)); + RefPtr certVerifier; + if (nssComponent) { + (void) nssComponent->GetDefaultCertVerifier(certVerifier); + } + return certVerifier; +} + +} } // namespace mozilla::psm diff --git a/startupcache/test/TestStartupCache.cpp b/startupcache/test/TestStartupCache.cpp index 1e78ec85263a..c5f07486e971 100644 --- a/startupcache/test/TestStartupCache.cpp +++ b/startupcache/test/TestStartupCache.cpp @@ -514,7 +514,7 @@ int main(int argc, char** argv) JSAutoRequest req(cx); static JSClass global_class = { "global", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE, - JS_PropertyStub, JS_PropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub diff --git a/storage/src/mozStorageService.cpp b/storage/src/mozStorageService.cpp index 2f8c69084167..75bd54696f89 100644 --- a/storage/src/mozStorageService.cpp +++ b/storage/src/mozStorageService.cpp @@ -163,13 +163,6 @@ public: return NS_OK; } - NS_IMETHOD GetExplicitNonHeap(int64_t *aAmount) - { - // This reporter doesn't do any non-heap measurements. - *aAmount = 0; - return NS_OK; - } - private: /** * Passes a single SQLite memory statistic to a memory multi-reporter diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index d1bd46e454f0..2b71260ce60d 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -39,7 +39,6 @@ const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE; const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE; - let explicitAmounts = []; let vsizeAmounts = []; let residentAmounts = []; let jsGcHeapAmounts = []; @@ -60,9 +59,7 @@ function handleReport(aProcess, aPath, aKind, aUnits, aAmount, aDescription) { // Record the values of some notable reporters. - if (aPath === "explicit") { - explicitAmounts.push(aAmount); - } else if (aPath === "vsize") { + if (aPath === "vsize") { vsizeAmounts.push(aAmount); } else if (aPath === "resident") { residentAmounts.push(aAmount); @@ -122,10 +119,8 @@ let r = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter); r.collectReports(handleReport, null); - // Access |name| and |explicitNonHeap| to make sure they don't crash or - // assert. + // Access |name| to make sure it doesn't crash or assert. dummy = r.name; - dummy = r.explicitNonHeap; } function checkSpecialReport(aName, aAmounts) @@ -139,7 +134,6 @@ // If mgr.explicit failed, we won't have "heap-allocated" either. if (haveExplicit) { - checkSpecialReport("explicit", explicitAmounts); checkSpecialReport("heap-allocated", heapAllocatedAmounts); } checkSpecialReport("vsize", vsizeAmounts); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 34a5a2679dd3..92ac84da765a 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -268,14 +268,6 @@ "n_buckets": 25, "description": "Ratio of committed, unused memory to allocated memory in the heap (percentage)." }, - "MEMORY_EXPLICIT": { - "kind": "exponential", - "low": 1024, - "high": "16 * 1024 * 1024", - "n_buckets": 200, - "extended_statistics_ok": true, - "description": "Explicit memory allocations (KB)" - }, "GHOST_WINDOWS": { "kind": "exponential", "high": "128", diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index c80725fc5234..222c96496660 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -694,7 +694,7 @@ WrapAndReturnHistogram(Histogram *h, JSContext *cx, JS::Value *ret) static JSClass JSHistogram_class = { "JSHistogram", /* name */ JSCLASS_HAS_PRIVATE, /* flags */ - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index ea56e3bcdd3a..7314c51a5347 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -58,12 +58,13 @@ const RWX_OWNER = 0700; // * MEMORY_JS_GC_HEAP, and // * MEMORY_JS_COMPARTMENTS_SYSTEM. // +// We used to measure "explicit" too, but it could cause hangs, and the data +// was always really noisy anyway. See bug 859657. const MEM_HISTOGRAMS = { "js-gc-heap": "MEMORY_JS_GC_HEAP", "js-compartments/system": "MEMORY_JS_COMPARTMENTS_SYSTEM", "js-compartments/user": "MEMORY_JS_COMPARTMENTS_USER", "js-main-runtime-temporary-peak": "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK", - "explicit": "MEMORY_EXPLICIT", "resident-fast": "MEMORY_RESIDENT", "vsize": "MEMORY_VSIZE", "storage-sqlite": "MEMORY_STORAGE_SQLITE", diff --git a/tools/profiler/SaveProfileTask.h b/tools/profiler/SaveProfileTask.h index 9e9d4ea561f4..afe8a0f94261 100644 --- a/tools/profiler/SaveProfileTask.h +++ b/tools/profiler/SaveProfileTask.h @@ -82,7 +82,7 @@ public: JSAutoRequest ar(cx); static JSClass c = { "global", JSCLASS_GLOBAL_FLAGS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; JSObject *obj = JS_NewGlobalObject(cx, &c, NULL); diff --git a/xpcom/base/MapsMemoryReporter.cpp b/xpcom/base/MapsMemoryReporter.cpp index 692484bc9e95..e95ddf112e44 100644 --- a/xpcom/base/MapsMemoryReporter.cpp +++ b/xpcom/base/MapsMemoryReporter.cpp @@ -128,13 +128,6 @@ public: CollectReports(nsIMemoryMultiReporterCallback *aCb, nsISupports *aClosure); - NS_IMETHOD - GetExplicitNonHeap(int64_t *aAmount) { - // This reporter doesn't do any "explicit" measurements. - *aAmount = 0; - return NS_OK; - } - private: // Search through /proc/self/maps for libxul.so, and set mLibxulDir to the // the directory containing libxul. diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 7d8b933ad7fb..b50af97af7f2 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2431,13 +2431,6 @@ class CycleCollectorMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter return NS_OK; } - NS_IMETHOD GetExplicitNonHeap(int64_t* n) - { - // This reporter does neither "explicit" nor NONHEAP measurements. - *n = 0; - return NS_OK; - } - private: NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf) diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index c248a4fa043c..2ea043c54453 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -199,7 +199,7 @@ interface nsIMemoryMultiReporterCallback : nsISupports * (Compare and contrast this with nsIMemoryReporter, which allows all * fields except |amount| to be accessed without triggering computation.) */ -[scriptable, uuid(61d498d5-b460-4398-a8ea-7f75208534b4)] +[scriptable, uuid(24d61ead-237b-4969-a6bd-73fd8fed1d99)] interface nsIMemoryMultiReporter : nsISupports { /* @@ -214,18 +214,6 @@ interface nsIMemoryMultiReporter : nsISupports */ void collectReports(in nsIMemoryMultiReporterCallback callback, in nsISupports closure); - - /* - * Return the sum of all this multi-reporter's measurements that have a - * path that starts with "explicit" and are KIND_NONHEAP. - * - * This is a hack that's required to implement - * nsIMemoryReporterManager::explicit efficiently, which is important -- - * multi-reporters can special-case this operation so it's much faster - * than getting all the reports, filtering out the unneeded ones, and - * summing the remainder. - */ - readonly attribute int64_t explicitNonHeap; }; [scriptable, builtinclass, uuid(70b0e608-8dbf-4dc7-b88f-f1c745c1b48c)] diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 4bf20c351b45..b498c4b28f89 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -594,27 +594,6 @@ private: return (int64_t) stats.allocated; } }; - -// The computation of "explicit" fails if "heap-allocated" isn't available, -// which is why this is depends on HAVE_JEMALLOC_STATS. -class ExplicitReporter MOZ_FINAL : public MemoryReporterBase -{ -public: - ExplicitReporter() - : MemoryReporterBase("explicit", KIND_OTHER, UNITS_BYTES, -"This is the same measurement as the root of the 'explicit' tree. However, " -"it is measured at a different time and so gives slightly different results.") - {} - - NS_IMETHOD GetAmount(int64_t *aAmount) - { - nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (mgr == nullptr) - return NS_ERROR_FAILURE; - - return mgr->GetExplicit(aAmount); - } -}; #endif // HAVE_JEMALLOC_STATS // Why is this here? At first glance, you'd think it could be defined and @@ -690,13 +669,6 @@ public: return NS_OK; } - - NS_IMETHOD GetExplicitNonHeap(int64_t *n) - { - // No non-heap allocations. - *n = 0; - return NS_OK; - } }; NS_IMPL_ISUPPORTS1(DMDMultiReporter, nsIMemoryMultiReporter) @@ -727,7 +699,6 @@ nsMemoryReporterManager::Init() RegisterReporter(new HeapCommittedUnusedReporter); RegisterReporter(new HeapCommittedUnusedRatioReporter); RegisterReporter(new HeapDirtyReporter); - RegisterReporter(new ExplicitReporter); #endif #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS @@ -1020,7 +991,6 @@ nsMemoryReporterManager::GetResident(int64_t *aResident) #endif } -#if defined(DEBUG) && !defined(MOZ_DMD) // This is just a wrapper for int64_t that implements nsISupports, so it can be // passed to nsIMemoryMultiReporter::CollectReports. class Int64Wrapper MOZ_FINAL : public nsISupports { @@ -1056,7 +1026,6 @@ NS_IMPL_ISUPPORTS1( ExplicitNonHeapCountingCallback , nsIMemoryMultiReporterCallback ) -#endif // defined(DEBUG) && !defined(MOZ_DMD) NS_IMETHODIMP nsMemoryReporterManager::GetExplicit(int64_t *aExplicit) @@ -1107,54 +1076,23 @@ nsMemoryReporterManager::GetExplicit(int64_t *aExplicit) } } - // For each multi-reporter we could call CollectReports and filter out the - // non-explicit, non-NONHEAP measurements. But that's lots of wasted work, - // so we instead use GetExplicitNonHeap() which exists purely for this - // purpose. - // - // (Actually, in debug builds we also do it the slow way and compare the - // result to the result obtained from GetExplicitNonHeap(). This - // guarantees the two measurement paths are equivalent. This is wise - // because it's easy for memory reporters to have bugs. But there's an - // exception if DMD is enabled, because that makes DMD think that all the - // blocks are double-counted.) + // For each multi-reporter we call CollectReports and filter out the + // non-explicit, non-NONHEAP measurements. That's lots of wasted work, + // and we used to have a GetExplicitNonHeap() method which did this more + // efficiently, but it ended up being more trouble than it was worth. - int64_t explicitNonHeapMultiSize = 0; + nsRefPtr cb = + new ExplicitNonHeapCountingCallback(); + nsRefPtr wrappedExplicitNonHeapMultiSize = + new Int64Wrapper(); nsCOMPtr e2; EnumerateMultiReporters(getter_AddRefs(e2)); while (NS_SUCCEEDED(e2->HasMoreElements(&more)) && more) { nsCOMPtr r; e2->GetNext(getter_AddRefs(r)); - int64_t n; - rv = r->GetExplicitNonHeap(&n); - NS_ENSURE_SUCCESS(rv, rv); - explicitNonHeapMultiSize += n; + r->CollectReports(cb, wrappedExplicitNonHeapMultiSize); } - -#if defined(DEBUG) && !defined(MOZ_DMD) - nsRefPtr cb = - new ExplicitNonHeapCountingCallback(); - nsRefPtr wrappedExplicitNonHeapMultiSize2 = - new Int64Wrapper(); - nsCOMPtr e3; - EnumerateMultiReporters(getter_AddRefs(e3)); - while (NS_SUCCEEDED(e3->HasMoreElements(&more)) && more) { - nsCOMPtr r; - e3->GetNext(getter_AddRefs(r)); - r->CollectReports(cb, wrappedExplicitNonHeapMultiSize2); - } - int64_t explicitNonHeapMultiSize2 = wrappedExplicitNonHeapMultiSize2->mValue; - - // Check the two measurements give the same result. This was an - // NS_ASSERTION but they occasionally don't match due to races (bug - // 728990). - if (explicitNonHeapMultiSize != explicitNonHeapMultiSize2) { - NS_WARNING(nsPrintfCString("The two measurements of 'explicit' memory " - "usage don't match (%lld vs %lld)", - explicitNonHeapMultiSize, - explicitNonHeapMultiSize2).get()); - } -#endif // defined(DEBUG) && !defined(MOZ_DMD) + int64_t explicitNonHeapMultiSize = wrappedExplicitNonHeapMultiSize->mValue; *aExplicit = heapAllocated + explicitNonHeapNormalSize + explicitNonHeapMultiSize; return NS_OK; diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 1e548d35380a..ec8afdbf1c67 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -48,6 +48,7 @@ #include "xptinfo.h" #include "nsIInterfaceInfoManager.h" #include "xptiprivate.h" +#include "mozilla/XPTInterfaceInfoManager.h" #include "nsTimerImpl.h" #include "TimerThread.h" @@ -126,6 +127,7 @@ extern nsresult nsStringInputStreamConstructor(nsISupports *, REFNSIID, void **) #include "GeckoProfiler.h" +using namespace mozilla; using base::AtExitManager; using mozilla::ipc::BrowserProcessSubThread; #ifdef MOZ_VISUAL_EVENT_TRACER @@ -228,7 +230,7 @@ nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer, NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); nsCOMPtr iim - (xptiInterfaceInfoManager::GetSingleton()); + (XPTInterfaceInfoManager::GetSingleton()); if (!iim) return NS_ERROR_FAILURE; @@ -470,7 +472,7 @@ NS_InitXPCOM2(nsIServiceManager* *result, // The iimanager constructor searches and registers XPT files. // (We trigger the singleton's lazy construction here to make that happen.) - (void) xptiInterfaceInfoManager::GetSingleton(); + (void) XPTInterfaceInfoManager::GetSingleton(); // After autoreg, but before we actually instantiate any components, // add any services listed in the "xpcom-directory-providers" category @@ -688,7 +690,7 @@ ShutdownXPCOM(nsIServiceManager* servMgr) // Do this _after_ shutting down the component manager, because the // JS component loader will use XPConnect to call nsIModule::canUnload, // and that will spin up the InterfaceInfoManager again -- bad mojo - xptiInterfaceInfoManager::FreeInterfaceInfoManager(); + XPTInterfaceInfoManager::FreeInterfaceInfoManager(); // Finally, release the component manager last because it unloads the // libraries: diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index a2298a746c42..b2d7d6d80773 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -36,6 +36,7 @@ #include "nsCategoryManager.h" #include "nsCategoryManagerUtils.h" #include "xptiprivate.h" +#include "mozilla/XPTInterfaceInfoManager.h" #include "nsIConsoleService.h" #include "nsIMemoryReporter.h" #include "nsIObserverService.h" @@ -613,8 +614,7 @@ nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, c rv = data.Copy(buf, len); } if (NS_SUCCEEDED(rv)) { - xptiInterfaceInfoManager::GetSingleton() - ->RegisterBuffer(buf, len); + XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len); } else { nsCString uri; f.GetURIString(uri); diff --git a/xpcom/reflect/xptcall/src/xptcall.cpp b/xpcom/reflect/xptcall/src/xptcall.cpp index ed0b99227f77..e46ddd559d3d 100644 --- a/xpcom/reflect/xptcall/src/xptcall.cpp +++ b/xpcom/reflect/xptcall/src/xptcall.cpp @@ -7,6 +7,9 @@ #include "xptcprivate.h" #include "xptiprivate.h" +#include "mozilla/XPTInterfaceInfoManager.h" + +using namespace mozilla; NS_IMETHODIMP nsXPTCStubBase::QueryInterface(REFNSIID aIID, @@ -39,8 +42,8 @@ NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, { NS_ENSURE_ARG(aOuter && aResult); - xptiInterfaceInfoManager *iim = - xptiInterfaceInfoManager::GetSingleton(); + XPTInterfaceInfoManager *iim = + XPTInterfaceInfoManager::GetSingleton(); NS_ENSURE_TRUE(iim, NS_ERROR_NOT_INITIALIZED); xptiInterfaceEntry *iie = iim->GetInterfaceEntryForIID(&aIID); diff --git a/xpcom/reflect/xptinfo/public/Makefile.in b/xpcom/reflect/xptinfo/public/Makefile.in index 9cab747bc2fb..8adec75ca937 100644 --- a/xpcom/reflect/xptinfo/public/Makefile.in +++ b/xpcom/reflect/xptinfo/public/Makefile.in @@ -15,6 +15,11 @@ EXPORTS = \ xptinfo.h \ $(NULL) +EXPORTS_NAMESPACES := mozilla +EXPORTS_mozilla := \ + XPTInterfaceInfoManager.h \ + $(null) + EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) include $(topsrcdir)/config/rules.mk diff --git a/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h b/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h new file mode 100644 index 000000000000..1fddf395f4f5 --- /dev/null +++ b/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=4 et sw=4 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_XPTInterfaceInfoManager_h_ +#define mozilla_XPTInterfaceInfoManager_h_ + +#include "nsIInterfaceInfoManager.h" + +#include "mozilla/Mutex.h" +#include "mozilla/ReentrantMonitor.h" +#include "nsDataHashtable.h" + +template class nsCOMArray; +class XPTHeader; +class XPTInterfaceDirectoryEntry; +class xptiInterfaceEntry; +class xptiInterfaceInfo; +class xptiTypelibGuts; + +namespace mozilla { + +class XPTInterfaceInfoManager MOZ_FINAL + : public nsIInterfaceInfoManager +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEINFOMANAGER + +public: + // GetSingleton() is infallible + static XPTInterfaceInfoManager* GetSingleton(); + static void FreeInterfaceInfoManager(); + + void GetScriptableInterfaces(nsCOMArray& aInterfaces); + + void RegisterBuffer(char *buf, uint32_t length); + + static Mutex& GetResolveLock() + { + return GetSingleton()->mResolveLock; + } + + xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid); + + size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf); + + static int64_t GetXPTIWorkingSetSize(); + +private: + XPTInterfaceInfoManager(); + ~XPTInterfaceInfoManager(); + + void RegisterXPTHeader(XPTHeader* aHeader); + + // idx is the index of this interface in the XPTHeader + void VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, + uint16_t idx, + xptiTypelibGuts* typelib); + +private: + + class xptiWorkingSet + { + public: + xptiWorkingSet(); + ~xptiWorkingSet(); + + bool IsValid() const; + + void InvalidateInterfaceInfos(); + void ClearHashTables(); + + // utility methods... + + enum {NOT_FOUND = 0xffffffff}; + + // Directory stuff... + + uint32_t GetDirectoryCount(); + nsresult GetCloneOfDirectoryAt(uint32_t i, nsIFile** dir); + nsresult GetDirectoryAt(uint32_t i, nsIFile** dir); + bool FindDirectory(nsIFile* dir, uint32_t* index); + bool FindDirectoryOfFile(nsIFile* file, uint32_t* index); + bool DirectoryAtMatchesPersistentDescriptor(uint32_t i, const char* desc); + + private: + uint32_t mFileCount; + uint32_t mMaxFileCount; + + public: + // XXX make these private with accessors + // mTableMonitor must be held across: + // * any read from or write to mIIDTable or mNameTable + // * any writing to the links between an xptiInterfaceEntry + // and its xptiInterfaceInfo (mEntry/mInfo) + mozilla::ReentrantMonitor mTableReentrantMonitor; + nsDataHashtable mIIDTable; + nsDataHashtable mNameTable; + }; + + // XXX xptiInterfaceInfo want's to poke at the working set itself + friend class ::xptiInterfaceInfo; + friend class ::xptiInterfaceEntry; + friend class ::xptiTypelibGuts; + + xptiWorkingSet mWorkingSet; + Mutex mResolveLock; +}; + +} + +#endif diff --git a/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl b/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl index 1789728a2655..f0db98a2f6e1 100644 --- a/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl +++ b/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl @@ -12,7 +12,7 @@ #include "nsISimpleEnumerator.idl" /* this is NOT intended to be scriptable */ -[uuid(8B161900-BE2B-11d2-9831-006008962422)] +[uuid(1d53d8d9-1d92-428f-b5cc-198b55e897d7)] interface nsIInterfaceInfoManager : nsISupports { nsIInterfaceInfo getInfoForIID(in nsIIDPtr iid); @@ -21,23 +21,11 @@ interface nsIInterfaceInfoManager : nsISupports nsIIDPtr getIIDForName(in string name); string getNameForIID(in nsIIDPtr iid); - nsIEnumerator enumerateInterfaces(); - void autoRegisterInterfaces(); nsIEnumerator enumerateInterfacesWhoseNamesStartWith(in string prefix); }; -[uuid(0ee22850-bc6a-11d5-9134-0010a4e73d9a)] -interface nsIInterfaceInfoSuperManager : nsIInterfaceInfoManager -{ - void addAdditionalManager(in nsIInterfaceInfoManager manager); - void removeAdditionalManager(in nsIInterfaceInfoManager manager); - - boolean hasAdditionalManagers(); - nsISimpleEnumerator enumerateAdditionalManagers(); -}; - %{C++ #define NS_INTERFACEINFOMANAGER_SERVICE_CID \ { /* 13bef784-f8e0-4f96-85c1-09f9ef4f9a19 */ \ diff --git a/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp b/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp index 60ab60d1fc87..3a27a78bfcd6 100644 --- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp +++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp @@ -6,6 +6,7 @@ /* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */ #include "xptiprivate.h" +#include "mozilla/XPTInterfaceInfoManager.h" #include "nsAtomicRefcnt.h" using namespace mozilla; @@ -70,7 +71,7 @@ xptiInterfaceEntry::xptiInterfaceEntry(const char* name, bool xptiInterfaceEntry::Resolve() { - MutexAutoLock lock(xptiInterfaceInfoManager::GetResolveLock()); + MutexAutoLock lock(XPTInterfaceInfoManager::GetResolveLock()); return ResolveLocked(); } @@ -540,7 +541,7 @@ nsresult xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info) { #ifdef DEBUG - xptiInterfaceInfoManager::GetSingleton()->GetWorkingSet()->mTableReentrantMonitor. + XPTInterfaceInfoManager::GetSingleton()->mWorkingSet.mTableReentrantMonitor. AssertCurrentThreadIn(); #endif LOG_INFO_MONITOR_ENTRY; @@ -572,8 +573,8 @@ xptiInterfaceEntry::LockedInvalidateInterfaceInfo() bool xptiInterfaceInfo::BuildParent() { - mozilla::ReentrantMonitorAutoEnter monitor(xptiInterfaceInfoManager::GetSingleton()-> - GetWorkingSet()->mTableReentrantMonitor); + mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::GetSingleton()-> + mWorkingSet.mTableReentrantMonitor); NS_ASSERTION(mEntry && mEntry->IsFullyResolved() && !mParent && @@ -615,8 +616,8 @@ xptiInterfaceInfo::Release(void) NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo"); if(!cnt) { - mozilla::ReentrantMonitorAutoEnter monitor(xptiInterfaceInfoManager:: - GetSingleton()->GetWorkingSet()-> + mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager:: + GetSingleton()->mWorkingSet. mTableReentrantMonitor); LOG_INFO_MONITOR_ENTRY; diff --git a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp index baf09a0c94b7..650c51dfb41e 100644 --- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp +++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -5,6 +5,8 @@ /* Implementation of xptiInterfaceInfoManager. */ +#include "mozilla/XPTInterfaceInfoManager.h" + #include "xptiprivate.h" #include "nsDependentString.h" #include "nsString.h" @@ -16,11 +18,10 @@ using namespace mozilla; -NS_IMPL_THREADSAFE_ISUPPORTS2(xptiInterfaceInfoManager, - nsIInterfaceInfoManager, - nsIInterfaceInfoSuperManager) +NS_IMPL_THREADSAFE_ISUPPORTS1(XPTInterfaceInfoManager, + nsIInterfaceInfoManager) -static xptiInterfaceInfoManager* gInterfaceInfoManager = nullptr; +static XPTInterfaceInfoManager* gInterfaceInfoManager = nullptr; #ifdef DEBUG static int gCallCount = 0; #endif @@ -29,7 +30,7 @@ static int gCallCount = 0; NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(XPTMallocSizeOf) size_t -xptiInterfaceInfoManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) +XPTInterfaceInfoManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) { size_t n = aMallocSizeOf(this); ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); @@ -42,7 +43,7 @@ xptiInterfaceInfoManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) // static int64_t -xptiInterfaceInfoManager::GetXPTIWorkingSetSize() +XPTInterfaceInfoManager::GetXPTIWorkingSetSize() { size_t n = XPT_SizeOfArena(gXPTIStructArena, XPTMallocSizeOf); @@ -53,40 +54,38 @@ xptiInterfaceInfoManager::GetXPTIWorkingSetSize() return n; } -NS_MEMORY_REPORTER_IMPLEMENT(xptiWorkingSet, +NS_MEMORY_REPORTER_IMPLEMENT(XPTInterfaceInfoManager, "explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, - xptiInterfaceInfoManager::GetXPTIWorkingSetSize, + XPTInterfaceInfoManager::GetXPTIWorkingSetSize, "Memory used by the XPCOM typelib system.") // static -xptiInterfaceInfoManager* -xptiInterfaceInfoManager::GetSingleton() +XPTInterfaceInfoManager* +XPTInterfaceInfoManager::GetSingleton() { if (!gInterfaceInfoManager) { - gInterfaceInfoManager = new xptiInterfaceInfoManager(); + gInterfaceInfoManager = new XPTInterfaceInfoManager(); NS_ADDREF(gInterfaceInfoManager); } return gInterfaceInfoManager; } void -xptiInterfaceInfoManager::FreeInterfaceInfoManager() +XPTInterfaceInfoManager::FreeInterfaceInfoManager() { NS_IF_RELEASE(gInterfaceInfoManager); } -xptiInterfaceInfoManager::xptiInterfaceInfoManager() +XPTInterfaceInfoManager::XPTInterfaceInfoManager() : mWorkingSet(), - mResolveLock("xptiInterfaceInfoManager.mResolveLock"), - mAdditionalManagersLock( - "xptiInterfaceInfoManager.mAdditionalManagersLock") + mResolveLock("XPTInterfaceInfoManager.mResolveLock") { - NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(xptiWorkingSet)); + NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPTInterfaceInfoManager)); } -xptiInterfaceInfoManager::~xptiInterfaceInfoManager() +XPTInterfaceInfoManager::~XPTInterfaceInfoManager() { // We only do this on shutdown of the service. mWorkingSet.InvalidateInterfaceInfos(); @@ -98,7 +97,7 @@ xptiInterfaceInfoManager::~xptiInterfaceInfoManager() } void -xptiInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length) +XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length) { XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length); if (!state) @@ -119,7 +118,7 @@ xptiInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length) } void -xptiInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader) +XPTInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader) { if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) { NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt"); @@ -134,9 +133,9 @@ xptiInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader) } void -xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, - uint16_t idx, - xptiTypelibGuts* typelib) +XPTInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, + uint16_t idx, + xptiTypelibGuts* typelib) { if (!iface->interface_descriptor) return; @@ -202,14 +201,15 @@ EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval) } xptiInterfaceEntry* -xptiInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid) +XPTInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid) { ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); return mWorkingSet.mIIDTable.Get(*iid); } /* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */ -NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) +NS_IMETHODIMP +XPTInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) { NS_ASSERTION(iid, "bad param"); NS_ASSERTION(_retval, "bad param"); @@ -220,7 +220,8 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInte } /* nsIInterfaceInfo getInfoForName (in string name); */ -NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) +NS_IMETHODIMP +XPTInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) { NS_ASSERTION(name, "bad param"); NS_ASSERTION(_retval, "bad param"); @@ -231,7 +232,8 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInte } /* nsIIDPtr getIIDForName (in string name); */ -NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) +NS_IMETHODIMP +XPTInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) { NS_ASSERTION(name, "bad param"); NS_ASSERTION(_retval, "bad param"); @@ -247,7 +249,8 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * } /* string getNameForIID (in nsIIDPtr iid); */ -NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval) +NS_IMETHODIMP +XPTInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval) { NS_ASSERTION(iid, "bad param"); NS_ASSERTION(_retval, "bad param"); @@ -265,31 +268,30 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char ** static PLDHashOperator xpti_ArrayAppender(const char* name, xptiInterfaceEntry* entry, void* arg) { - nsISupportsArray* array = (nsISupportsArray*) arg; + nsCOMArray* array = static_cast*>(arg); nsCOMPtr ii; - if (NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + if (NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) { + bool scriptable = false; + ii->IsScriptable(&scriptable); + if (scriptable) { array->AppendElement(ii); + } + } return PL_DHASH_NEXT; } /* nsIEnumerator enumerateInterfaces (); */ -NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_retval) +void +XPTInterfaceInfoManager::GetScriptableInterfaces(nsCOMArray& aInterfaces) { // I didn't want to incur the size overhead of using nsHashtable just to // make building an enumerator easier. So, this code makes a snapshot of // the table using an nsISupportsArray and builds an enumerator for that. // We can afford this transient cost. - nsCOMPtr array; - NS_NewISupportsArray(getter_AddRefs(array)); - if (!array) - return NS_ERROR_UNEXPECTED; - ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); - mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayAppender, array); - - return array->Enumerate(_retval); + mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayAppender, &aInterfaces); } struct ArrayAndPrefix @@ -315,7 +317,8 @@ xpti_ArrayPrefixAppender(const char* keyname, xptiInterfaceEntry* entry, void* a } /* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */ -NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) +NS_IMETHODIMP +XPTInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) { nsCOMPtr array; NS_NewISupportsArray(getter_AddRefs(array)); @@ -330,78 +333,8 @@ NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(c } /* void autoRegisterInterfaces (); */ -NS_IMETHODIMP xptiInterfaceInfoManager::AutoRegisterInterfaces() +NS_IMETHODIMP +XPTInterfaceInfoManager::AutoRegisterInterfaces() { return NS_ERROR_NOT_IMPLEMENTED; } - -/***************************************************************************/ - -/* void addAdditionalManager (in nsIInterfaceInfoManager manager); */ -NS_IMETHODIMP xptiInterfaceInfoManager::AddAdditionalManager(nsIInterfaceInfoManager *manager) -{ - nsCOMPtr weakRef = do_GetWeakReference(manager); - nsISupports* ptrToAdd = weakRef ? - static_cast(weakRef) : - static_cast(manager); - { // scoped lock... - MutexAutoLock lock(mAdditionalManagersLock); - if (mAdditionalManagers.IndexOf(ptrToAdd) != -1) - return NS_ERROR_FAILURE; - if (!mAdditionalManagers.AppendObject(ptrToAdd)) - return NS_ERROR_OUT_OF_MEMORY; - } - return NS_OK; -} - -/* void removeAdditionalManager (in nsIInterfaceInfoManager manager); */ -NS_IMETHODIMP xptiInterfaceInfoManager::RemoveAdditionalManager(nsIInterfaceInfoManager *manager) -{ - nsCOMPtr weakRef = do_GetWeakReference(manager); - nsISupports* ptrToRemove = weakRef ? - static_cast(weakRef) : - static_cast(manager); - { // scoped lock... - MutexAutoLock lock(mAdditionalManagersLock); - if (!mAdditionalManagers.RemoveObject(ptrToRemove)) - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -/* bool hasAdditionalManagers (); */ -NS_IMETHODIMP xptiInterfaceInfoManager::HasAdditionalManagers(bool *_retval) -{ - *_retval = mAdditionalManagers.Count() > 0; - return NS_OK; -} - -/* nsISimpleEnumerator enumerateAdditionalManagers (); */ -NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateAdditionalManagers(nsISimpleEnumerator **_retval) -{ - MutexAutoLock lock(mAdditionalManagersLock); - - nsCOMArray managerArray(mAdditionalManagers); - /* Resolve all the weak references in the array. */ - for(int32_t i = managerArray.Count(); i--; ) { - nsISupports *raw = managerArray.ObjectAt(i); - if (!raw) - return NS_ERROR_FAILURE; - nsCOMPtr weakRef = do_QueryInterface(raw); - if (weakRef) { - nsCOMPtr manager = - do_QueryReferent(weakRef); - if (manager) { - if (!managerArray.ReplaceObjectAt(manager, i)) - return NS_ERROR_FAILURE; - } - else { - // The manager is no more. Remove the element. - mAdditionalManagers.RemoveObjectAt(i); - managerArray.RemoveObjectAt(i); - } - } - } - - return NS_NewArrayEnumerator(_retval, managerArray); -} diff --git a/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp b/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp index 6f9a65cc666c..ada3f9abbaed 100644 --- a/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp +++ b/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp @@ -6,6 +6,7 @@ /* Implementation of xptiTypelibGuts. */ #include "xptiprivate.h" +#include "mozilla/XPTInterfaceInfoManager.h" using namespace mozilla; @@ -38,15 +39,15 @@ xptiTypelibGuts::GetEntryAt(uint16_t i) XPTInterfaceDirectoryEntry* iface = mHeader->interface_directory + i; - xptiWorkingSet* set = - xptiInterfaceInfoManager::GetSingleton()->GetWorkingSet(); + XPTInterfaceInfoManager::xptiWorkingSet& set = + XPTInterfaceInfoManager::GetSingleton()->mWorkingSet; { - ReentrantMonitorAutoEnter monitor(set->mTableReentrantMonitor); + ReentrantMonitorAutoEnter monitor(set.mTableReentrantMonitor); if (iface->iid.Equals(zeroIID)) - r = set->mNameTable.Get(iface->name); + r = set.mNameTable.Get(iface->name); else - r = set->mIIDTable.Get(iface->iid); + r = set.mIIDTable.Get(iface->iid); } if (r) diff --git a/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp b/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp index 5f6331061955..9eee6d473944 100644 --- a/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp +++ b/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp @@ -5,6 +5,8 @@ /* Implementation of xptiWorkingSet. */ +#include "mozilla/XPTInterfaceInfoManager.h" + #include "xptiprivate.h" #include "nsString.h" @@ -13,7 +15,7 @@ using namespace mozilla; #define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 16) #define XPTI_HASHTABLE_SIZE 2048 -xptiWorkingSet::xptiWorkingSet() +XPTInterfaceInfoManager::xptiWorkingSet::xptiWorkingSet() : mTableReentrantMonitor("xptiWorkingSet::mTableReentrantMonitor") { MOZ_COUNT_CTOR(xptiWorkingSet); @@ -33,13 +35,13 @@ xpti_Invalidator(const char* keyname, xptiInterfaceEntry* entry, void* arg) } void -xptiWorkingSet::InvalidateInterfaceInfos() +XPTInterfaceInfoManager::xptiWorkingSet::InvalidateInterfaceInfos() { ReentrantMonitorAutoEnter monitor(mTableReentrantMonitor); mNameTable.EnumerateRead(xpti_Invalidator, NULL); } -xptiWorkingSet::~xptiWorkingSet() +XPTInterfaceInfoManager::xptiWorkingSet::~xptiWorkingSet() { MOZ_COUNT_DTOR(xptiWorkingSet); diff --git a/xpcom/reflect/xptinfo/src/xptiprivate.h b/xpcom/reflect/xptinfo/src/xptiprivate.h index f179b3a9cd26..8637d70a9189 100644 --- a/xpcom/reflect/xptinfo/src/xptiprivate.h +++ b/xpcom/reflect/xptinfo/src/xptiprivate.h @@ -75,7 +75,6 @@ class xptiInterfaceInfo; class xptiInterfaceInfoManager; class xptiInterfaceEntry; class xptiTypelibGuts; -class xptiWorkingSet; extern XPTArena* gXPTIStructArena; @@ -117,45 +116,6 @@ private: /***************************************************************************/ -class xptiWorkingSet -{ -public: - xptiWorkingSet(); - ~xptiWorkingSet(); - - bool IsValid() const; - - void InvalidateInterfaceInfos(); - void ClearHashTables(); - - // utility methods... - - enum {NOT_FOUND = 0xffffffff}; - - // Directory stuff... - - uint32_t GetDirectoryCount(); - nsresult GetCloneOfDirectoryAt(uint32_t i, nsIFile** dir); - nsresult GetDirectoryAt(uint32_t i, nsIFile** dir); - bool FindDirectory(nsIFile* dir, uint32_t* index); - bool FindDirectoryOfFile(nsIFile* file, uint32_t* index); - bool DirectoryAtMatchesPersistentDescriptor(uint32_t i, const char* desc); - -private: - uint32_t mFileCount; - uint32_t mMaxFileCount; - -public: - // XXX make these private with accessors - // mTableMonitor must be held across: - // * any read from or write to mIIDTable or mNameTable - // * any writing to the links between an xptiInterfaceEntry - // and its xptiInterfaceInfo (mEntry/mInfo) - mozilla::ReentrantMonitor mTableReentrantMonitor; - nsDataHashtable mIIDTable; - nsDataHashtable mNameTable; -}; - /***************************************************************************/ // This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value @@ -396,53 +356,4 @@ private: /***************************************************************************/ -class xptiInterfaceInfoManager MOZ_FINAL - : public nsIInterfaceInfoSuperManager -{ - NS_DECL_ISUPPORTS - NS_DECL_NSIINTERFACEINFOMANAGER - NS_DECL_NSIINTERFACEINFOSUPERMANAGER - - typedef mozilla::ReentrantMonitor ReentrantMonitor; - typedef mozilla::Mutex Mutex; - -public: - // GetSingleton() is infallible - static xptiInterfaceInfoManager* GetSingleton(); - static void FreeInterfaceInfoManager(); - - void RegisterBuffer(char *buf, uint32_t length); - - xptiWorkingSet* GetWorkingSet() {return &mWorkingSet;} - - static Mutex& GetResolveLock(xptiInterfaceInfoManager* self = nullptr) - { - self = self ? self : GetSingleton(); - return self->mResolveLock; - } - - xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid); - - size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf); - - static int64_t GetXPTIWorkingSetSize(); - -private: - xptiInterfaceInfoManager(); - ~xptiInterfaceInfoManager(); - - void RegisterXPTHeader(XPTHeader* aHeader); - - // idx is the index of this interface in the XPTHeader - void VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, - uint16_t idx, - xptiTypelibGuts* typelib); - -private: - xptiWorkingSet mWorkingSet; - Mutex mResolveLock; - Mutex mAdditionalManagersLock; - nsCOMArray mAdditionalManagers; -}; - #endif /* xptiprivate_h___ */