mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
fababd0f52
@ -696,6 +696,7 @@
|
||||
#ifdef MOZ_DEBUG
|
||||
@RESPATH@/components/TestInterfaceJS.js
|
||||
@RESPATH@/components/TestInterfaceJS.manifest
|
||||
@RESPATH@/components/TestInterfaceJSMaplike.js
|
||||
#endif
|
||||
|
||||
@RESPATH@/components/PACGenerator.js
|
||||
|
@ -1677,6 +1677,9 @@ pref("browser.newtabpage.updateIntroShown", false);
|
||||
// Toggles the content of 'about:newtab'. Shows the grid when enabled.
|
||||
pref("browser.newtabpage.enabled", true);
|
||||
|
||||
// Toggles the enhanced content of 'about:newtab'. Shows sponsored tiles.
|
||||
sticky_pref("browser.newtabpage.enhanced", true);
|
||||
|
||||
// number of rows of newtab grid
|
||||
pref("browser.newtabpage.rows", 3);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
const PREF_INTRO_SHOWN = "browser.newtabpage.introShown";
|
||||
const PREF_UPDATE_INTRO_SHOWN = "browser.newtabpage.updateIntroShown";
|
||||
const PREF_NEWTAB_ENHANCED = "browser.newtabpage.enhanced";
|
||||
|
||||
// These consts indicate the type of intro/onboarding we show.
|
||||
const WELCOME = "welcome";
|
||||
@ -205,6 +206,9 @@ let gIntro = {
|
||||
},
|
||||
|
||||
showIfNecessary: function() {
|
||||
if (!Services.prefs.getBoolPref(PREF_NEWTAB_ENHANCED)) {
|
||||
return;
|
||||
}
|
||||
if (!Services.prefs.getBoolPref(PREF_INTRO_SHOWN)) {
|
||||
this._onboardingType = WELCOME;
|
||||
this.showPanel();
|
||||
|
@ -54,6 +54,7 @@ let gPage = {
|
||||
// Update thumbnails to the new enhanced setting
|
||||
if (aData == "browser.newtabpage.enhanced") {
|
||||
this.update();
|
||||
gIntro.showIfNecessary();
|
||||
}
|
||||
|
||||
// Initialize the whole page if we haven't done that, yet.
|
||||
|
@ -16,7 +16,6 @@ support-files =
|
||||
title.sjs
|
||||
|
||||
[browser_privatebrowsing_DownloadLastDirWithCPS.js]
|
||||
skip-if = (os == "win" && os_version == "6.2") # bug 1173801
|
||||
[browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
|
||||
[browser_privatebrowsing_aboutSessionRestore.js]
|
||||
[browser_privatebrowsing_cache.js]
|
||||
|
@ -623,6 +623,7 @@
|
||||
#ifdef MOZ_DEBUG
|
||||
@RESPATH@/components/TestInterfaceJS.js
|
||||
@RESPATH@/components/TestInterfaceJS.manifest
|
||||
@RESPATH@/components/TestInterfaceJSMaplike.js
|
||||
#endif
|
||||
|
||||
@RESPATH@/components/PACGenerator.js
|
||||
|
@ -388,7 +388,7 @@ let DirectoryLinksProvider = {
|
||||
*/
|
||||
_setDefaultEnhanced: function DirectoryLinksProvider_setDefaultEnhanced() {
|
||||
if (!Services.prefs.prefHasUserValue(PREF_NEWTAB_ENHANCED)) {
|
||||
let enhanced = true;
|
||||
let enhanced = Services.prefs.getBoolPref(PREF_NEWTAB_ENHANCED);
|
||||
try {
|
||||
// Default to not enhanced if DNT is set to tell websites to not track
|
||||
if (Services.prefs.getBoolPref("privacy.donottrackheader.enabled")) {
|
||||
|
@ -4585,8 +4585,7 @@ nsDocShell::GetDocument()
|
||||
nsPIDOMWindow*
|
||||
nsDocShell::GetWindow()
|
||||
{
|
||||
NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
|
||||
return mScriptGlobal;
|
||||
return NS_SUCCEEDED(EnsureScriptEnvironment()) ? mScriptGlobal : nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -613,7 +613,7 @@ void
|
||||
Link::CreateSearchParamsIfNeeded()
|
||||
{
|
||||
if (!mSearchParams) {
|
||||
mSearchParams = new URLSearchParams(this);
|
||||
mSearchParams = new URLSearchParams(this, this);
|
||||
UpdateURLSearchParams();
|
||||
}
|
||||
}
|
||||
|
@ -26,12 +26,12 @@ namespace dom {
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(URL)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
|
||||
if (tmp->mSearchParams) {
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@ -42,22 +42,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
URL::URL(already_AddRefed<nsIURI> aURI)
|
||||
: mURI(aURI)
|
||||
URL::URL(nsISupports* aParent, already_AddRefed<nsIURI> aURI)
|
||||
: mParent(aParent)
|
||||
, mURI(aURI)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
|
||||
JSObject*
|
||||
URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return URLBinding::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
return URLBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<URL>
|
||||
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
URL& aBase, ErrorResult& aRv)
|
||||
{
|
||||
return Constructor(aUrl, aBase.GetURI(), aRv);
|
||||
return Constructor(aGlobal.GetAsSupports(), aUrl, aBase.GetURI(), aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<URL>
|
||||
@ -65,22 +66,22 @@ URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
const Optional<nsAString>& aBase, ErrorResult& aRv)
|
||||
{
|
||||
if (aBase.WasPassed()) {
|
||||
return Constructor(aUrl, aBase.Value(), aRv);
|
||||
return Constructor(aGlobal.GetAsSupports(), aUrl, aBase.Value(), aRv);
|
||||
}
|
||||
|
||||
return Constructor(aUrl, nullptr, aRv);
|
||||
return Constructor(aGlobal.GetAsSupports(), aUrl, nullptr, aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<URL>
|
||||
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
const nsAString& aBase, ErrorResult& aRv)
|
||||
{
|
||||
return Constructor(aUrl, aBase, aRv);
|
||||
return Constructor(aGlobal.GetAsSupports(), aUrl, aBase, aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<URL>
|
||||
URL::Constructor(const nsAString& aUrl, const nsAString& aBase,
|
||||
ErrorResult& aRv)
|
||||
URL::Constructor(nsISupports* aParent, const nsAString& aUrl,
|
||||
const nsAString& aBase, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIURI> baseUri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase, nullptr, nullptr,
|
||||
@ -90,12 +91,13 @@ URL::Constructor(const nsAString& aUrl, const nsAString& aBase,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Constructor(aUrl, baseUri, aRv);
|
||||
return Constructor(aParent, aUrl, baseUri, aRv);
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<URL>
|
||||
URL::Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv)
|
||||
URL::Constructor(nsISupports* aParent, const nsAString& aUrl, nsIURI* aBase,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl, nullptr, aBase,
|
||||
@ -105,7 +107,7 @@ URL::Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<URL> url = new URL(uri.forget());
|
||||
nsRefPtr<URL> url = new URL(aParent, uri.forget());
|
||||
return url.forget();
|
||||
}
|
||||
|
||||
@ -533,7 +535,7 @@ void
|
||||
URL::CreateSearchParamsIfNeeded()
|
||||
{
|
||||
if (!mSearchParams) {
|
||||
mSearchParams = new URLSearchParams(this);
|
||||
mSearchParams = new URLSearchParams(mParent, this);
|
||||
UpdateURLSearchParams();
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsISupports;
|
||||
class nsIURI;
|
||||
@ -32,6 +33,7 @@ class URLProxy;
|
||||
}
|
||||
|
||||
class URL final : public URLSearchParamsObserver
|
||||
, public nsWrapperCache
|
||||
{
|
||||
~URL() {}
|
||||
|
||||
@ -39,11 +41,16 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(URL)
|
||||
|
||||
explicit URL(already_AddRefed<nsIURI> aURI);
|
||||
URL(nsISupports* aParent, already_AddRefed<nsIURI> aURI);
|
||||
|
||||
// WebIDL methods
|
||||
bool
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector);
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static already_AddRefed<URL>
|
||||
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
@ -56,9 +63,11 @@ public:
|
||||
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
const nsAString& aBase, ErrorResult& aRv);
|
||||
static already_AddRefed<URL>
|
||||
Constructor(const nsAString& aUrl, const nsAString& aBase, ErrorResult& aRv);
|
||||
Constructor(nsISupports* aParent, const nsAString& aUrl,
|
||||
const nsAString& aBase, ErrorResult& aRv);
|
||||
static already_AddRefed<URL>
|
||||
Constructor(const nsAString& aUrl, nsIURI* aBase, ErrorResult& aRv);
|
||||
Constructor(nsISupports* aParent, const nsAString& aUrl,
|
||||
nsIURI* aBase, ErrorResult& aRv);
|
||||
|
||||
static void CreateObjectURL(const GlobalObject& aGlobal,
|
||||
Blob& aBlob,
|
||||
@ -150,6 +159,7 @@ private:
|
||||
nsAString& aResult,
|
||||
ErrorResult& aError);
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsRefPtr<URLSearchParams> mSearchParams;
|
||||
|
||||
|
@ -293,7 +293,7 @@ URLParams::Serialize(nsAString& aValue) const
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mParent, mObserver)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
|
||||
|
||||
@ -302,13 +302,19 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
URLSearchParams::URLSearchParams(URLSearchParamsObserver* aObserver)
|
||||
: mParams(new URLParams()), mObserver(aObserver)
|
||||
URLSearchParams::URLSearchParams(nsISupports* aParent,
|
||||
URLSearchParamsObserver* aObserver)
|
||||
: mParams(new URLParams())
|
||||
, mParent(aParent)
|
||||
, mObserver(aObserver)
|
||||
{
|
||||
}
|
||||
|
||||
URLSearchParams::URLSearchParams(const URLSearchParams& aOther)
|
||||
: mParams(new URLParams(*aOther.mParams.get())), mObserver(aOther.mObserver)
|
||||
URLSearchParams::URLSearchParams(nsISupports* aParent,
|
||||
const URLSearchParams& aOther)
|
||||
: mParams(new URLParams(*aOther.mParams.get()))
|
||||
, mParent(aParent)
|
||||
, mObserver(aOther.mObserver)
|
||||
{
|
||||
}
|
||||
|
||||
@ -328,8 +334,10 @@ URLSearchParams::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aInit,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<URLSearchParams> sp = new URLSearchParams(nullptr);
|
||||
nsRefPtr<URLSearchParams> sp =
|
||||
new URLSearchParams(aGlobal.GetAsSupports(), nullptr);
|
||||
sp->ParseInput(NS_ConvertUTF16toUTF8(aInit));
|
||||
|
||||
return sp.forget();
|
||||
}
|
||||
|
||||
@ -338,7 +346,9 @@ URLSearchParams::Constructor(const GlobalObject& aGlobal,
|
||||
URLSearchParams& aInit,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<URLSearchParams> sp = new URLSearchParams(aInit);
|
||||
nsRefPtr<URLSearchParams> sp =
|
||||
new URLSearchParams(aGlobal.GetAsSupports(), aInit);
|
||||
|
||||
return sp.forget();
|
||||
}
|
||||
|
||||
|
@ -114,14 +114,16 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URLSearchParams)
|
||||
|
||||
explicit URLSearchParams(URLSearchParamsObserver* aObserver);
|
||||
URLSearchParams(nsISupports* aParent,
|
||||
URLSearchParamsObserver* aObserver);
|
||||
|
||||
explicit URLSearchParams(const URLSearchParams& aOther);
|
||||
URLSearchParams(nsISupports* aParent,
|
||||
const URLSearchParams& aOther);
|
||||
|
||||
// WebIDL methods
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return nullptr;
|
||||
return mParent;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
@ -174,6 +176,7 @@ private:
|
||||
void NotifyObserver();
|
||||
|
||||
UniquePtr<URLParams> mParams;
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsRefPtr<URLSearchParamsObserver> mObserver;
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,7 @@ class nsIPrincipal;
|
||||
|
||||
class nsIGlobalObject : public nsISupports
|
||||
{
|
||||
nsTArray<nsCString> mHostObjectURIs;
|
||||
bool mIsDying;
|
||||
|
||||
protected:
|
||||
@ -69,10 +70,6 @@ public:
|
||||
protected:
|
||||
virtual ~nsIGlobalObject();
|
||||
|
||||
private:
|
||||
nsTArray<nsCString> mHostObjectURIs;
|
||||
|
||||
protected:
|
||||
void
|
||||
StartDying()
|
||||
{
|
||||
|
@ -1092,12 +1092,12 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
|
||||
case nsISupportsPrimitive::TYPE_PRTIME :
|
||||
case nsISupportsPrimitive::TYPE_VOID : {
|
||||
NS_WARNING("Unsupported primitive type used");
|
||||
*aArgv = JSVAL_NULL;
|
||||
aArgv->setNull();
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
NS_WARNING("Unknown primitive type used");
|
||||
*aArgv = JSVAL_NULL;
|
||||
aArgv->setNull();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2816,5 +2816,89 @@ SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
|
||||
ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
|
||||
}
|
||||
|
||||
template<decltype(JS::NewMapObject) Method>
|
||||
bool
|
||||
GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
size_t aSlotIndex,
|
||||
JS::MutableHandle<JSObject*> aBackingObj,
|
||||
bool* aBackingObjCreated)
|
||||
{
|
||||
JS::Rooted<JSObject*> reflector(aCx);
|
||||
reflector = IsDOMObject(aObj) ? aObj : js::UncheckedUnwrap(aObj,
|
||||
/* stopAtOuter = */ false);
|
||||
|
||||
// Retrieve the backing object from the reserved slot on the maplike/setlike
|
||||
// object. If it doesn't exist yet, create it.
|
||||
JS::Rooted<JS::Value> slotValue(aCx);
|
||||
slotValue = js::GetReservedSlot(reflector, aSlotIndex);
|
||||
if (slotValue.isUndefined()) {
|
||||
// Since backing object access can happen in non-originating compartments,
|
||||
// make sure to create the backing object in reflector compartment.
|
||||
{
|
||||
JSAutoCompartment ac(aCx, reflector);
|
||||
JS::Rooted<JSObject*> newBackingObj(aCx);
|
||||
newBackingObj.set(Method(aCx));
|
||||
if (NS_WARN_IF(!newBackingObj)) {
|
||||
return false;
|
||||
}
|
||||
js::SetReservedSlot(reflector, aSlotIndex, JS::ObjectValue(*newBackingObj));
|
||||
}
|
||||
slotValue = js::GetReservedSlot(reflector, aSlotIndex);
|
||||
*aBackingObjCreated = true;
|
||||
} else {
|
||||
*aBackingObjCreated = false;
|
||||
}
|
||||
if (!MaybeWrapNonDOMObjectValue(aCx, &slotValue)) {
|
||||
return false;
|
||||
}
|
||||
aBackingObj.set(&slotValue.toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
size_t aSlotIndex,
|
||||
JS::MutableHandle<JSObject*> aBackingObj,
|
||||
bool* aBackingObjCreated)
|
||||
{
|
||||
return GetMaplikeSetlikeBackingObject<JS::NewMapObject>(aCx, aObj, aSlotIndex,
|
||||
aBackingObj,
|
||||
aBackingObjCreated);
|
||||
}
|
||||
|
||||
bool
|
||||
GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
size_t aSlotIndex,
|
||||
JS::MutableHandle<JSObject*> aBackingObj,
|
||||
bool* aBackingObjCreated)
|
||||
{
|
||||
return GetMaplikeSetlikeBackingObject<JS::NewSetObject>(aCx, aObj, aSlotIndex,
|
||||
aBackingObj,
|
||||
aBackingObjCreated);
|
||||
}
|
||||
|
||||
bool
|
||||
ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
||||
{
|
||||
JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
|
||||
// Unpack callback and object from slots
|
||||
JS::Rooted<JS::Value>
|
||||
callbackFn(aCx, js::GetFunctionNativeReserved(&args.callee(),
|
||||
FOREACH_CALLBACK_SLOT));
|
||||
JS::Rooted<JS::Value>
|
||||
maplikeOrSetlikeObj(aCx,
|
||||
js::GetFunctionNativeReserved(&args.callee(),
|
||||
FOREACH_MAPLIKEORSETLIKEOBJ_SLOT));
|
||||
MOZ_ASSERT(aArgc == 3);
|
||||
JS::AutoValueVector newArgs(aCx);
|
||||
// Arguments are passed in as value, key, object. Keep value and key, replace
|
||||
// object with the maplike/setlike object.
|
||||
newArgs.append(args.get(0));
|
||||
newArgs.append(args.get(1));
|
||||
newArgs.append(maplikeOrSetlikeObj);
|
||||
JS::Rooted<JS::Value> rval(aCx, JS::UndefinedValue());
|
||||
// Now actually call the user specified callback
|
||||
return JS::Call(aCx, args.thisv(), callbackFn, newArgs, &rval);
|
||||
}
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -3248,6 +3248,29 @@ bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
// thrown.
|
||||
bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
// Slot indexes for maplike/setlike forEach functions
|
||||
#define FOREACH_CALLBACK_SLOT 0
|
||||
#define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
|
||||
|
||||
// Backing function for running .forEach() on maplike/setlike interfaces.
|
||||
// Unpacks callback and maplike/setlike object from reserved slots, then runs
|
||||
// callback for each key (and value, for maplikes)
|
||||
bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
|
||||
|
||||
// Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
|
||||
// for a maplike/setlike interface. If backing object does not exist, creates
|
||||
// backing object in the compartment of the reflector involved, making this safe
|
||||
// to use across compartments/via xrays. Return values of these methods will
|
||||
// always be in the context compartment.
|
||||
bool GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
size_t aSlotIndex,
|
||||
JS::MutableHandle<JSObject*> aBackingObj,
|
||||
bool* aBackingObjCreated);
|
||||
bool GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
size_t aSlotIndex,
|
||||
JS::MutableHandle<JSObject*> aBackingObj,
|
||||
bool* aBackingObjCreated);
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -1308,12 +1308,9 @@ DOMInterfaces = {
|
||||
'implicitJSContext' : [ 'undo', 'redo', 'transact' ],
|
||||
},
|
||||
|
||||
'URL' : [{
|
||||
'wrapperCache': False,
|
||||
},
|
||||
'URL' : [{},
|
||||
{
|
||||
'workers': True,
|
||||
'wrapperCache': False,
|
||||
}],
|
||||
|
||||
'VRDevice': {
|
||||
|
@ -1143,6 +1143,18 @@ class CGHeaders(CGWrapper):
|
||||
if funcList is not None:
|
||||
addHeaderForFunc(funcList[0])
|
||||
|
||||
for desc in descriptors:
|
||||
if desc.interface.maplikeOrSetlike:
|
||||
# We need ToJSValue.h for maplike/setlike type conversions
|
||||
bindingHeaders.add("mozilla/dom/ToJSValue.h")
|
||||
# Add headers for the key and value types of the maplike, since
|
||||
# they'll be needed for convenience functions
|
||||
addHeadersForType((desc.interface.maplikeOrSetlike.keyType,
|
||||
desc, None))
|
||||
if desc.interface.maplikeOrSetlike.valueType:
|
||||
addHeadersForType((desc.interface.maplikeOrSetlike.valueType,
|
||||
desc, None))
|
||||
|
||||
for d in dictionaries:
|
||||
if d.parent:
|
||||
declareIncludes.add(self.getDeclarationFilename(d.parent))
|
||||
@ -2164,7 +2176,9 @@ class MethodDefiner(PropertyDefiner):
|
||||
"name": m.identifier.name,
|
||||
"methodInfo": not m.isStatic(),
|
||||
"length": methodLength(m),
|
||||
"flags": "JSPROP_ENUMERATE",
|
||||
# Methods generated for a maplike/setlike declaration are not
|
||||
# enumerable.
|
||||
"flags": "JSPROP_ENUMERATE" if not m.isMaplikeOrSetlikeMethod() else "0",
|
||||
"condition": PropertyDefiner.getControllingCondition(m, descriptor),
|
||||
"allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
|
||||
"returnsPromise": m.returnsPromise(),
|
||||
@ -2175,9 +2189,21 @@ class MethodDefiner(PropertyDefiner):
|
||||
else:
|
||||
self.regular.append(method)
|
||||
|
||||
# FIXME Check for an existing iterator on the interface first.
|
||||
if (any(m.isGetter() and m.isIndexed() for m in methods) and
|
||||
not any("@@iterator" in m.aliases for m in methods)):
|
||||
# TODO: Once iterable is implemented, use tiebreak rules instead of
|
||||
# failing. Also, may be more tiebreak rules to implement once spec bug
|
||||
# is resolved.
|
||||
# https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
|
||||
def hasIterator(methods, regular):
|
||||
return (any("@@iterator" in m.aliases for m in methods) or
|
||||
any("@@iterator" == r["name"] for r in regular))
|
||||
|
||||
if (any(m.isGetter() and m.isIndexed() for m in methods)):
|
||||
if hasIterator(methods, self.regular):
|
||||
raise TypeError("Cannot have indexed getter/attr on "
|
||||
"interface %s with other members "
|
||||
"that generate @@iterator, such as "
|
||||
"maplike/setlike or aliased functions." %
|
||||
self.descriptor.interface.identifier.name)
|
||||
self.regular.append({
|
||||
"name": "@@iterator",
|
||||
"methodInfo": False,
|
||||
@ -2187,6 +2213,31 @@ class MethodDefiner(PropertyDefiner):
|
||||
"condition": MemberCondition(None, None)
|
||||
})
|
||||
|
||||
# Generate the maplike/setlike iterator, if one wasn't already
|
||||
# generated by a method. If we already have an @@iterator symbol, fail.
|
||||
if descriptor.interface.maplikeOrSetlike:
|
||||
if hasIterator(methods, self.regular):
|
||||
raise TypeError("Cannot have maplike/setlike interface with "
|
||||
"other members that generate @@iterator "
|
||||
"on interface %s, such as indexed getters "
|
||||
"or aliased functions." %
|
||||
self.descriptor.interface.identifier.name)
|
||||
for m in methods:
|
||||
if (m.isMaplikeOrSetlikeMethod() and
|
||||
((m.maplikeOrSetlike.isMaplike() and
|
||||
m.identifier.name == "entries") or
|
||||
(m.maplikeOrSetlike.isSetlike() and
|
||||
m.identifier.name == "values"))):
|
||||
self.regular.append({
|
||||
"name": "@@iterator",
|
||||
"methodName": m.identifier.name,
|
||||
"length": methodLength(m),
|
||||
"flags": "0",
|
||||
"condition": PropertyDefiner.getControllingCondition(m,
|
||||
descriptor),
|
||||
})
|
||||
break
|
||||
|
||||
if not static:
|
||||
stringifier = descriptor.operations['Stringifier']
|
||||
if (stringifier and
|
||||
@ -2284,7 +2335,9 @@ class MethodDefiner(PropertyDefiner):
|
||||
jitinfo = "nullptr"
|
||||
else:
|
||||
selfHostedName = "nullptr"
|
||||
accessor = m.get("nativeName", IDLToCIdentifier(m["name"]))
|
||||
# When defining symbols, function name may not match symbol name
|
||||
methodName = m.get("methodName", m["name"])
|
||||
accessor = m.get("nativeName", IDLToCIdentifier(methodName))
|
||||
if m.get("methodInfo", True):
|
||||
# Cast this in case the methodInfo is a
|
||||
# JSTypedMethodJitInfo.
|
||||
@ -2377,8 +2430,10 @@ class AttrDefiner(PropertyDefiner):
|
||||
|
||||
def flags(attr):
|
||||
unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
|
||||
return ("JSPROP_SHARED | JSPROP_ENUMERATE" +
|
||||
unforgeable)
|
||||
# Attributes generated as part of a maplike/setlike declaration are
|
||||
# not enumerable.
|
||||
enumerable = " | JSPROP_ENUMERATE" if not attr.isMaplikeOrSetlikeAttr() else ""
|
||||
return ("JSPROP_SHARED" + enumerable + unforgeable)
|
||||
|
||||
def getter(attr):
|
||||
if self.static:
|
||||
@ -5539,7 +5594,7 @@ class CGArgumentConverter(CGThing):
|
||||
will be automatically uppercased.
|
||||
"""
|
||||
def __init__(self, argument, index, descriptorProvider,
|
||||
argDescription,
|
||||
argDescription, member,
|
||||
invalidEnumValueFatal=True, lenientFloatCode=None):
|
||||
CGThing.__init__(self)
|
||||
self.argument = argument
|
||||
@ -5556,8 +5611,16 @@ class CGArgumentConverter(CGThing):
|
||||
"obj": "obj",
|
||||
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptorProvider))
|
||||
}
|
||||
self.replacementVariables["val"] = string.Template(
|
||||
"args[${index}]").substitute(replacer)
|
||||
# If we have a method generated by the maplike/setlike portion of an
|
||||
# interface, arguments can possibly be undefined, but will need to be
|
||||
# converted to the key/value type of the backing object. In this case,
|
||||
# use .get() instead of direct access to the argument.
|
||||
if member.isMethod() and member.isMaplikeOrSetlikeMethod():
|
||||
self.replacementVariables["val"] = string.Template(
|
||||
"args.get(${index})").substitute(replacer)
|
||||
else:
|
||||
self.replacementVariables["val"] = string.Template(
|
||||
"args[${index}]").substitute(replacer)
|
||||
haveValueCheck = string.Template(
|
||||
"args.hasDefined(${index})").substitute(replacer)
|
||||
self.replacementVariables["haveValue"] = haveValueCheck
|
||||
@ -6795,7 +6858,7 @@ class CGPerSignatureCall(CGThing):
|
||||
cgThings.append(
|
||||
CGArgumentConverter(arguments[i], i, self.descriptor,
|
||||
argDescription % {"index": i + 1},
|
||||
invalidEnumValueFatal=not setter,
|
||||
idlNode, invalidEnumValueFatal=not setter,
|
||||
lenientFloatCode=lenientFloatCode))
|
||||
|
||||
if needsUnwrap:
|
||||
@ -6832,11 +6895,19 @@ class CGPerSignatureCall(CGThing):
|
||||
CGIfWrapper(CGList(xraySteps),
|
||||
"objIsXray"))
|
||||
|
||||
cgThings.append(CGCallGenerator(
|
||||
self.getErrorReport() if self.isFallible() else None,
|
||||
self.getArguments(), argsPre, returnType,
|
||||
self.extendedAttributes, descriptor, nativeMethodName,
|
||||
static, argsPost=argsPost, resultVar=resultVar))
|
||||
# If this is a method that was generated by a maplike/setlike
|
||||
# interface, use the maplike/setlike generator to fill in the body.
|
||||
# Otherwise, use CGCallGenerator to call the native method.
|
||||
if idlNode.isMethod() and idlNode.isMaplikeOrSetlikeMethod():
|
||||
cgThings.append(CGMaplikeOrSetlikeMethodGenerator(descriptor,
|
||||
idlNode.maplikeOrSetlike,
|
||||
idlNode.identifier.name))
|
||||
else:
|
||||
cgThings.append(CGCallGenerator(
|
||||
self.getErrorReport() if self.isFallible() else None,
|
||||
self.getArguments(), argsPre, returnType,
|
||||
self.extendedAttributes, descriptor, nativeMethodName,
|
||||
static, argsPost=argsPost, resultVar=resultVar))
|
||||
self.cgRoot = CGList(cgThings)
|
||||
|
||||
def getArguments(self):
|
||||
@ -7051,7 +7122,10 @@ class CGMethodCall(CGThing):
|
||||
self.cgRoot = CGList([getPerSignatureCall(signature)])
|
||||
requiredArgs = requiredArgCount(signature)
|
||||
|
||||
if requiredArgs > 0:
|
||||
# Skip required arguments check for maplike/setlike interfaces, as
|
||||
# they can have arguments which are not passed, and are treated as
|
||||
# if undefined had been explicitly passed.
|
||||
if requiredArgs > 0 and not method.isMaplikeOrSetlikeMethod():
|
||||
code = fill(
|
||||
"""
|
||||
if (MOZ_UNLIKELY(args.length() < ${requiredArgs})) {
|
||||
@ -7146,7 +7220,7 @@ class CGMethodCall(CGThing):
|
||||
# possibleSignatures[0]
|
||||
caseBody = [CGArgumentConverter(possibleSignatures[0][1][i],
|
||||
i, descriptor,
|
||||
argDesc % (i + 1))
|
||||
argDesc % (i + 1), method)
|
||||
for i in range(0, distinguishingIndex)]
|
||||
|
||||
# Select the right overload from our set.
|
||||
@ -7438,7 +7512,12 @@ class FakeArgument():
|
||||
self.variadic = False
|
||||
self.defaultValue = None
|
||||
self._allowTreatNonCallableAsNull = allowTreatNonCallableAsNull
|
||||
self.treatNullAs = interfaceMember.treatNullAs
|
||||
# For FakeArguments generated by maplike/setlike convenience functions,
|
||||
# we won't have an interfaceMember to pass in.
|
||||
if interfaceMember:
|
||||
self.treatNullAs = interfaceMember.treatNullAs
|
||||
else:
|
||||
self.treatNullAs = "Default"
|
||||
if isinstance(interfaceMember, IDLAttribute):
|
||||
self.enforceRange = interfaceMember.enforceRange
|
||||
self.clamp = interfaceMember.clamp
|
||||
@ -8008,6 +8087,12 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
|
||||
|
||||
def definition_body(self):
|
||||
if self.attr.maplikeOrSetlike:
|
||||
# If the interface is maplike/setlike, there will be one getter
|
||||
# method for the size property of the backing object. Due to having
|
||||
# to unpack the backing object from the slot, this requires its own
|
||||
# generator.
|
||||
return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
|
||||
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
|
||||
self.attr)
|
||||
if self.attr.slotIndex is not None:
|
||||
@ -11263,6 +11348,10 @@ class CGDescriptor(CGThing):
|
||||
crossOriginMethods.add(m.identifier.name)
|
||||
if m.getExtendedAttribute("MethodIdentityTestable"):
|
||||
cgThings.append(CGMethodIdentityTest(descriptor, m))
|
||||
# If we've hit the maplike/setlike member itself, go ahead and
|
||||
# generate its convenience functions.
|
||||
elif m.isMaplikeOrSetlike():
|
||||
cgThings.append(CGMaplikeOrSetlikeHelperGenerator(descriptor, m))
|
||||
elif m.isAttr():
|
||||
if m.stringifier:
|
||||
raise TypeError("Stringifier attributes not supported yet. "
|
||||
@ -12438,6 +12527,15 @@ class CGForwardDeclarations(CGWrapper):
|
||||
# Needed for at least Wrap.
|
||||
for d in descriptors:
|
||||
builder.add(d.nativeType)
|
||||
# If we're an interface and we have a maplike/setlike declaration,
|
||||
# we'll have helper functions exposed to the native side of our
|
||||
# bindings, which will need to show up in the header. If either of
|
||||
# our key/value types are interfaces, they'll be passed as
|
||||
# arguments to helper functions, and they'll need to be forward
|
||||
# declared in the header.
|
||||
if d.interface.maplikeOrSetlike:
|
||||
forwardDeclareForType(d.interface.maplikeOrSetlike.keyType)
|
||||
forwardDeclareForType(d.interface.maplikeOrSetlike.valueType)
|
||||
|
||||
# We just about always need NativePropertyHooks
|
||||
builder.addInMozillaDom("NativePropertyHooks", isStruct=True)
|
||||
@ -14070,8 +14168,12 @@ class FakeMember():
|
||||
|
||||
|
||||
class CallbackMember(CGNativeMember):
|
||||
# XXXbz It's OK to use CallbackPreserveColor for wrapScope because
|
||||
# CallSetup already handled the unmark-gray bits for us. we don't have
|
||||
# anything better to use for 'obj', really...
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling,
|
||||
rethrowContentException=False, typedArraysAreStructs=False):
|
||||
rethrowContentException=False, typedArraysAreStructs=False,
|
||||
wrapScope='CallbackPreserveColor()'):
|
||||
"""
|
||||
needThisHandling is True if we need to be able to accept a specified
|
||||
thisObj, False otherwise.
|
||||
@ -14095,6 +14197,8 @@ class CallbackMember(CGNativeMember):
|
||||
# will handle generating public versions that handle the "this" stuff.
|
||||
visibility = "private" if needThisHandling else "public"
|
||||
self.rethrowContentException = rethrowContentException
|
||||
|
||||
self.wrapScope = wrapScope
|
||||
# We don't care, for callback codegen, whether our original member was
|
||||
# a method or attribute or whatnot. Just always pass FakeMember()
|
||||
# here.
|
||||
@ -14214,10 +14318,7 @@ class CallbackMember(CGNativeMember):
|
||||
'successCode': "continue;\n" if arg.variadic else "break;\n",
|
||||
'jsvalRef': "argv[%s]" % jsvalIndex,
|
||||
'jsvalHandle': "argv[%s]" % jsvalIndex,
|
||||
# XXXbz we don't have anything better to use for 'obj',
|
||||
# really... It's OK to use CallbackPreserveColor because
|
||||
# CallSetup already handled the unmark-gray bits for us.
|
||||
'obj': 'CallbackPreserveColor()',
|
||||
'obj': self.wrapScope,
|
||||
'returnsNewObject': False,
|
||||
'exceptionCode': self.exceptionCode,
|
||||
'typedArraysAreStructs': self.typedArraysAreStructs
|
||||
@ -14546,6 +14647,497 @@ class CGJSImplInitOperation(CallbackOperationBase):
|
||||
return "__init"
|
||||
|
||||
|
||||
def getMaplikeOrSetlikeErrorReturn(helperImpl):
|
||||
"""
|
||||
Generate return values based on whether a maplike or setlike generated
|
||||
method is an interface method (which returns bool) or a helper function
|
||||
(which uses ErrorResult).
|
||||
"""
|
||||
if helperImpl:
|
||||
return dedent(
|
||||
"""
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return%s;
|
||||
""" % helperImpl.getDefaultRetval())
|
||||
return "return false;\n"
|
||||
|
||||
|
||||
def getMaplikeOrSetlikeBackingObject(descriptor, maplikeOrSetlike, helperImpl=None):
|
||||
"""
|
||||
Generate code to get/create a JS backing object for a maplike/setlike
|
||||
declaration from the declaration slot.
|
||||
"""
|
||||
func_prefix = maplikeOrSetlike.maplikeOrSetlikeType.title()
|
||||
ret = fill(
|
||||
"""
|
||||
JS::Rooted<JSObject*> backingObj(cx);
|
||||
bool created = false;
|
||||
if (!Get${func_prefix}BackingObject(cx, obj, ${slot}, &backingObj, &created)) {
|
||||
$*{errorReturn}
|
||||
}
|
||||
if (created) {
|
||||
PreserveWrapper<${selfType}>(self);
|
||||
}
|
||||
""",
|
||||
slot=memberReservedSlot(maplikeOrSetlike),
|
||||
func_prefix=func_prefix,
|
||||
errorReturn=getMaplikeOrSetlikeErrorReturn(helperImpl),
|
||||
selfType=descriptor.nativeType)
|
||||
return ret
|
||||
|
||||
|
||||
def getMaplikeOrSetlikeSizeGetterBody(descriptor, attr):
|
||||
"""
|
||||
Creates the body for the size getter method of maplike/setlike interfaces.
|
||||
"""
|
||||
# We should only have one declaration attribute currently
|
||||
assert attr.identifier.name == "size"
|
||||
assert attr.isMaplikeOrSetlikeAttr()
|
||||
return fill(
|
||||
"""
|
||||
$*{getBackingObj}
|
||||
uint32_t result = JS::${funcPrefix}Size(cx, backingObj);
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||
args.rval().setNumber(result);
|
||||
return true;
|
||||
""",
|
||||
getBackingObj=getMaplikeOrSetlikeBackingObject(descriptor,
|
||||
attr.maplikeOrSetlike),
|
||||
funcPrefix=attr.maplikeOrSetlike.prefix)
|
||||
|
||||
|
||||
class CGMaplikeOrSetlikeMethodGenerator(CGThing):
|
||||
"""
|
||||
Creates methods for maplike/setlike interfaces. It is expected that all
|
||||
methods will be have a maplike/setlike object attached. Unwrapping/wrapping
|
||||
will be taken care of by the usual method generation machinery in
|
||||
CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
|
||||
using CGCallGenerator.
|
||||
"""
|
||||
def __init__(self, descriptor, maplikeOrSetlike, methodName,
|
||||
helperImpl=None):
|
||||
CGThing.__init__(self)
|
||||
# True if this will be the body of a C++ helper function.
|
||||
self.helperImpl = helperImpl
|
||||
self.descriptor = descriptor
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self.cgRoot = CGList([])
|
||||
impl_method_name = methodName
|
||||
if impl_method_name[0] == "_":
|
||||
# double underscore means this is a js-implemented chrome only rw
|
||||
# function. Truncate the double underscore so calling the right
|
||||
# underlying JSAPI function still works.
|
||||
impl_method_name = impl_method_name[2:]
|
||||
self.cgRoot.append(CGGeneric(
|
||||
getMaplikeOrSetlikeBackingObject(self.descriptor,
|
||||
self.maplikeOrSetlike,
|
||||
self.helperImpl)))
|
||||
self.returnStmt = getMaplikeOrSetlikeErrorReturn(self.helperImpl)
|
||||
|
||||
# Generates required code for the method. Method descriptions included
|
||||
# in definitions below. Throw if we don't have a method to fill in what
|
||||
# we're looking for.
|
||||
try:
|
||||
methodGenerator = getattr(self, impl_method_name)
|
||||
except AttributeError:
|
||||
raise TypeError("Missing %s method definition '%s'" %
|
||||
(self.maplikeOrSetlike.maplikeOrSetlikeType,
|
||||
methodName))
|
||||
# Method generator returns tuple, containing:
|
||||
#
|
||||
# - a list of CGThings representing setup code for preparing to call
|
||||
# the JS API function
|
||||
# - a list of arguments needed for the JS API function we're calling
|
||||
# - list of code CGThings needed for return value conversion.
|
||||
(setupCode, arguments, setResult) = methodGenerator()
|
||||
|
||||
# Create the actual method call, and then wrap it with the code to
|
||||
# return the value if needed.
|
||||
funcName = (self.maplikeOrSetlike.prefix +
|
||||
MakeNativeName(impl_method_name))
|
||||
# Append the list of setup code CGThings
|
||||
self.cgRoot.append(CGList(setupCode))
|
||||
# Create the JS API call
|
||||
self.cgRoot.append(CGWrapper(
|
||||
CGGeneric(fill(
|
||||
"""
|
||||
if (!JS::${funcName}(${args})) {
|
||||
$*{errorReturn}
|
||||
}
|
||||
""",
|
||||
funcName=funcName,
|
||||
args=", ".join(["cx", "backingObj"] + arguments),
|
||||
errorReturn=self.returnStmt))))
|
||||
# Append result conversion
|
||||
self.cgRoot.append(CGList(setResult))
|
||||
|
||||
def mergeTuples(self, a, b):
|
||||
"""
|
||||
Expecting to take 2 tuples were all elements are lists, append the lists in
|
||||
the second tuple to the lists in the first.
|
||||
"""
|
||||
return tuple([x + y for x, y in zip(a, b)])
|
||||
|
||||
def appendArgConversion(self, name):
|
||||
"""
|
||||
Generate code to convert arguments to JS::Values, so they can be
|
||||
passed into JSAPI functions.
|
||||
"""
|
||||
return CGGeneric(fill(
|
||||
"""
|
||||
JS::Rooted<JS::Value> ${name}Val(cx);
|
||||
if (!ToJSValue(cx, ${name}, &${name}Val)) {
|
||||
$*{errorReturn}
|
||||
}
|
||||
""",
|
||||
name=name,
|
||||
errorReturn=self.returnStmt))
|
||||
|
||||
def appendKeyArgConversion(self):
|
||||
"""
|
||||
Generates the key argument for methods. Helper functions will use
|
||||
an AutoValueVector, while interface methods have seperate JS::Values.
|
||||
"""
|
||||
if self.helperImpl:
|
||||
return ([], ["argv[0]"], [])
|
||||
return ([self.appendArgConversion("arg0")], ["arg0Val"], [])
|
||||
|
||||
def appendKeyAndValueArgConversion(self):
|
||||
"""
|
||||
Generates arguments for methods that require a key and value. Helper
|
||||
functions will use an AutoValueVector, while interface methods have
|
||||
seperate JS::Values.
|
||||
"""
|
||||
r = self.appendKeyArgConversion()
|
||||
if self.helperImpl:
|
||||
return self.mergeTuples(r, ([], ["argv[1]"], []))
|
||||
return self.mergeTuples(r, ([self.appendArgConversion("arg1")],
|
||||
["arg1Val"],
|
||||
[]))
|
||||
|
||||
def appendIteratorResult(self):
|
||||
"""
|
||||
Generate code to output JSObject* return values, needed for functions that
|
||||
return iterators. Iterators cannot currently be wrapped via Xrays. If
|
||||
something that would return an iterator is called via Xray, fail early.
|
||||
"""
|
||||
# TODO: Bug 1173651 - Remove check once bug 1023984 is fixed.
|
||||
code = CGGeneric(dedent(
|
||||
"""
|
||||
// TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change
|
||||
// after bug 1023984 is fixed.
|
||||
if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
|
||||
JS_ReportError(cx, "Xray wrapping of iterators not supported.");
|
||||
return false;
|
||||
}
|
||||
JS::Rooted<JSObject*> result(cx);
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
"""))
|
||||
arguments = "&v"
|
||||
setResult = CGGeneric(dedent(
|
||||
"""
|
||||
result = &v.toObject();
|
||||
"""))
|
||||
return ([code], [arguments], [setResult])
|
||||
|
||||
def appendSelfResult(self):
|
||||
"""
|
||||
Generate code to return the interface object itself.
|
||||
"""
|
||||
code = CGGeneric(dedent(
|
||||
"""
|
||||
JS::Rooted<JSObject*> result(cx);
|
||||
"""))
|
||||
setResult = CGGeneric(dedent(
|
||||
"""
|
||||
result = obj;
|
||||
"""))
|
||||
return ([code], [], [setResult])
|
||||
|
||||
def appendBoolResult(self):
|
||||
if self.helperImpl:
|
||||
return ([CGGeneric()], ["&aRetVal"], [])
|
||||
return ([CGGeneric("bool result;\n")], ["&result"], [])
|
||||
|
||||
def forEach(self):
|
||||
"""
|
||||
void forEach(callback c, any thisval);
|
||||
|
||||
ForEach takes a callback, and a possible value to use as 'this'. The
|
||||
callback needs to take value, key, and the interface object
|
||||
implementing maplike/setlike. In order to make sure that the third arg
|
||||
is our interface object instead of the map/set backing object, we
|
||||
create a js function with the callback and original object in its
|
||||
storage slots, then use a helper function in BindingUtils to make sure
|
||||
the callback is called correctly.
|
||||
"""
|
||||
assert(not self.helperImpl)
|
||||
code = [CGGeneric(dedent(
|
||||
"""
|
||||
// Create a wrapper function.
|
||||
JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr);
|
||||
if (!func) {
|
||||
return false;
|
||||
}
|
||||
JS::Rooted<JSObject*> funcObj(cx, JS_GetFunctionObject(func));
|
||||
JS::Rooted<JS::Value> funcVal(cx, JS::ObjectValue(*funcObj));
|
||||
js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT,
|
||||
JS::ObjectValue(*arg0));
|
||||
js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT,
|
||||
JS::ObjectValue(*obj));
|
||||
"""))]
|
||||
arguments = ["funcVal", "arg1"]
|
||||
return (code, arguments, [])
|
||||
|
||||
def set(self):
|
||||
"""
|
||||
object set(key, value);
|
||||
|
||||
Maplike only function, takes key and sets value to it, returns
|
||||
interface object unless being called from a C++ helper.
|
||||
"""
|
||||
assert self.maplikeOrSetlike.isMaplike()
|
||||
r = self.appendKeyAndValueArgConversion()
|
||||
if self.helperImpl:
|
||||
return r
|
||||
return self.mergeTuples(r, self.appendSelfResult())
|
||||
|
||||
def add(self):
|
||||
"""
|
||||
object add(value);
|
||||
|
||||
Setlike only function, adds value to set, returns interface object
|
||||
unless being called from a C++ helper
|
||||
"""
|
||||
assert self.maplikeOrSetlike.isSetlike()
|
||||
r = self.appendKeyArgConversion()
|
||||
if self.helperImpl:
|
||||
return r
|
||||
return self.mergeTuples(r, self.appendSelfResult())
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
type? get(key);
|
||||
|
||||
Retrieves a value from a backing object based on the key. Returns value
|
||||
if key is in backing object, undefined otherwise.
|
||||
"""
|
||||
assert self.maplikeOrSetlike.isMaplike()
|
||||
r = self.appendKeyArgConversion()
|
||||
code = [CGGeneric(dedent(
|
||||
"""
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
"""))]
|
||||
arguments = ["&result"]
|
||||
return self.mergeTuples(r, (code, arguments, []))
|
||||
|
||||
def has(self):
|
||||
"""
|
||||
bool has(key);
|
||||
|
||||
Check if an entry exists in the backing object. Returns true if value
|
||||
exists in backing object, false otherwise.
|
||||
"""
|
||||
return self.mergeTuples(self.appendKeyArgConversion(),
|
||||
self.appendBoolResult())
|
||||
|
||||
def keys(self):
|
||||
"""
|
||||
object keys();
|
||||
|
||||
Returns new object iterator with all keys from backing object.
|
||||
"""
|
||||
return self.appendIteratorResult()
|
||||
|
||||
def values(self):
|
||||
"""
|
||||
object values();
|
||||
|
||||
Returns new object iterator with all values from backing object.
|
||||
"""
|
||||
return self.appendIteratorResult()
|
||||
|
||||
def entries(self):
|
||||
"""
|
||||
object entries();
|
||||
|
||||
Returns new object iterator with all keys and values from backing
|
||||
object. Keys will be null for set.
|
||||
"""
|
||||
return self.appendIteratorResult()
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
void clear();
|
||||
|
||||
Removes all entries from map/set.
|
||||
"""
|
||||
return ([], [], [])
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
bool delete(key);
|
||||
|
||||
Deletes an entry from the backing object. Returns true if value existed
|
||||
in backing object, false otherwise.
|
||||
"""
|
||||
return self.mergeTuples(self.appendKeyArgConversion(),
|
||||
self.appendBoolResult())
|
||||
|
||||
def define(self):
|
||||
return self.cgRoot.define()
|
||||
|
||||
|
||||
class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember):
|
||||
"""
|
||||
Generates code to allow C++ to perform operations on backing objects. Gets
|
||||
a context from the binding wrapper, turns arguments into JS::Values (via
|
||||
CallbackMember/CGNativeMember argument conversion), then uses
|
||||
CGMaplikeOrSetlikeMethodGenerator to generate the body.
|
||||
|
||||
"""
|
||||
|
||||
class HelperFunction(CGAbstractMethod):
|
||||
"""
|
||||
Generates context retrieval code and rooted JSObject for interface for
|
||||
CGMaplikeOrSetlikeMethodGenerator to use
|
||||
"""
|
||||
def __init__(self, descriptor, name, args, code, needsBoolReturn=False):
|
||||
self.code = code
|
||||
CGAbstractMethod.__init__(self, descriptor, name,
|
||||
"bool" if needsBoolReturn else "void",
|
||||
args)
|
||||
|
||||
def definition_body(self):
|
||||
return self.code
|
||||
|
||||
def __init__(self, descriptor, maplikeOrSetlike, name, needsKeyArg=False,
|
||||
needsValueArg=False, needsBoolReturn=False):
|
||||
args = []
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self.needsBoolReturn = needsBoolReturn
|
||||
if needsKeyArg:
|
||||
args.append(FakeArgument(maplikeOrSetlike.keyType, None, 'aKey'))
|
||||
if needsValueArg:
|
||||
assert needsKeyArg
|
||||
args.append(FakeArgument(maplikeOrSetlike.valueType, None, 'aValue'))
|
||||
# Run CallbackMember init function to generate argument conversion code.
|
||||
# wrapScope is set to 'obj' when generating maplike or setlike helper
|
||||
# functions, as we don't have access to the CallbackPreserveColor
|
||||
# method.
|
||||
CallbackMember.__init__(self,
|
||||
[BuiltinTypes[IDLBuiltinType.Types.void], args],
|
||||
name, descriptor, False,
|
||||
wrapScope='obj')
|
||||
# Wrap CallbackMember body code into a CGAbstractMethod to make
|
||||
# generation easier.
|
||||
self.implMethod = CGMaplikeOrSetlikeHelperFunctionGenerator.HelperFunction(
|
||||
descriptor, name, self.args, self.body, needsBoolReturn)
|
||||
|
||||
def getCallSetup(self):
|
||||
return dedent(
|
||||
"""
|
||||
MOZ_ASSERT(self);
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
jsapi.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment tempCompartment(cx, xpc::UnprivilegedJunkScope());
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
if(!ToJSValue(cx, self, &v)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return%s;
|
||||
}
|
||||
// This is a reflector, but due to trying to name things
|
||||
// similarly across method generators, it's called obj here.
|
||||
JS::Rooted<JSObject*> obj(cx);
|
||||
obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtOuter = */ false);
|
||||
JSAutoCompartment reflectorCompartment(cx, obj);
|
||||
""" % self.getDefaultRetval())
|
||||
|
||||
def getArgs(self, returnType, argList):
|
||||
# We don't need the context or the value. We'll generate those instead.
|
||||
args = CGNativeMember.getArgs(self, returnType, argList)
|
||||
# Prepend a pointer to the binding object onto the arguments
|
||||
return [Argument(self.descriptorProvider.nativeType + "*", "self")] + args
|
||||
|
||||
def getResultConversion(self):
|
||||
if self.needsBoolReturn:
|
||||
return "return aRetVal;\n"
|
||||
return "return;\n"
|
||||
|
||||
def getRvalDecl(self):
|
||||
if self.needsBoolReturn:
|
||||
return "bool aRetVal;\n"
|
||||
return ""
|
||||
|
||||
def getArgcDecl(self):
|
||||
# Don't need argc for anything.
|
||||
return None
|
||||
|
||||
def getDefaultRetval(self):
|
||||
if self.needsBoolReturn:
|
||||
return " false"
|
||||
return ""
|
||||
|
||||
|
||||
def getCall(self):
|
||||
return CGMaplikeOrSetlikeMethodGenerator(self.descriptorProvider,
|
||||
self.maplikeOrSetlike,
|
||||
self.name.lower(),
|
||||
helperImpl=self).define()
|
||||
|
||||
def getPrettyName(self):
|
||||
return self.name
|
||||
|
||||
def declare(self):
|
||||
return self.implMethod.declare()
|
||||
|
||||
def define(self):
|
||||
return self.implMethod.define()
|
||||
|
||||
|
||||
class CGMaplikeOrSetlikeHelperGenerator(CGNamespace):
|
||||
"""
|
||||
Declares and defines convenience methods for accessing backing objects on
|
||||
setlike/maplike interface. Generates function signatures, un/packs
|
||||
backing objects from slot, etc.
|
||||
"""
|
||||
def __init__(self, descriptor, maplikeOrSetlike):
|
||||
self.descriptor = descriptor
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self.namespace = "%sHelpers" % (self.maplikeOrSetlike.maplikeOrSetlikeType.title())
|
||||
self.helpers = [
|
||||
CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
|
||||
maplikeOrSetlike,
|
||||
"Clear"),
|
||||
CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
|
||||
maplikeOrSetlike,
|
||||
"Delete",
|
||||
needsKeyArg=True,
|
||||
needsBoolReturn=True),
|
||||
CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
|
||||
maplikeOrSetlike,
|
||||
"Has",
|
||||
needsKeyArg=True,
|
||||
needsBoolReturn=True)]
|
||||
if self.maplikeOrSetlike.isMaplike():
|
||||
self.helpers.append(
|
||||
CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
|
||||
maplikeOrSetlike,
|
||||
"Set",
|
||||
needsKeyArg=True,
|
||||
needsValueArg=True))
|
||||
else:
|
||||
assert(self.maplikeOrSetlike.isSetlike())
|
||||
self.helpers.append(
|
||||
CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
|
||||
maplikeOrSetlike,
|
||||
"Add",
|
||||
needsKeyArg=True))
|
||||
CGNamespace.__init__(self, self.namespace, CGList(self.helpers))
|
||||
|
||||
|
||||
class GlobalGenRoots():
|
||||
"""
|
||||
Roots for global codegen.
|
||||
|
@ -209,6 +209,15 @@ ToJSValue(JSContext* aCx,
|
||||
return ToJSValue(aCx, *aArgument.get(), aValue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const NonNull<T>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
return ToJSValue(aCx, *aArgument.get(), aValue);
|
||||
}
|
||||
|
||||
// Accept WebIDL dictionaries
|
||||
template <class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
|
@ -84,6 +84,25 @@ SOURCES += [
|
||||
'StructuredClone.cpp',
|
||||
]
|
||||
|
||||
# Tests for maplike and setlike require bindings to be built, which means they
|
||||
# must be included in libxul. This breaks the "no test classes are exported"
|
||||
# rule stated in the test/ directory, but it's the only way this will work.
|
||||
# Test classes are only built in debug mode, and all tests requiring use of
|
||||
# them are only run in debug mode.
|
||||
if CONFIG['MOZ_DEBUG']:
|
||||
EXPORTS.mozilla.dom += [
|
||||
"test/TestInterfaceMaplike.h",
|
||||
"test/TestInterfaceMaplikeObject.h",
|
||||
"test/TestInterfaceSetlike.h",
|
||||
"test/TestInterfaceSetlikeNode.h"
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
"test/TestInterfaceMaplike.cpp",
|
||||
"test/TestInterfaceMaplikeObject.cpp",
|
||||
"test/TestInterfaceSetlike.cpp",
|
||||
"test/TestInterfaceSetlikeNode.cpp",
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
if CONFIG['MOZ_AUDIO_CHANNEL_MANAGER']:
|
||||
|
@ -619,6 +619,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
self._callback = False
|
||||
self._finished = False
|
||||
self.members = []
|
||||
self.maplikeOrSetlike = None
|
||||
self._partialInterfaces = []
|
||||
self._extendedAttrDict = {}
|
||||
# namedConstructors needs deterministic ordering because bindings code
|
||||
@ -692,6 +693,27 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
self.addExtendedAttributes(partial.propagatedExtendedAttrs)
|
||||
self.members.extend(partial.members)
|
||||
|
||||
# Generate maplike/setlike interface members. Since generated members
|
||||
# need to be treated like regular interface members, do this before
|
||||
# things like exposure setting.
|
||||
for member in self.members:
|
||||
if member.isMaplikeOrSetlike():
|
||||
# Check that we only have one interface declaration (currently
|
||||
# there can only be one maplike/setlike declaration per
|
||||
# interface)
|
||||
if self.maplikeOrSetlike:
|
||||
raise WebIDLError("%s declaration used on "
|
||||
"interface that already has %s "
|
||||
"declaration" %
|
||||
(member.maplikeOrSetlikeType,
|
||||
self.maplikeOrSetlike.maplikeOrSetlikeType),
|
||||
[self.maplikeOrSetlike.location,
|
||||
member.location])
|
||||
self.maplikeOrSetlike = member
|
||||
# If we've got a maplike or setlike declaration, we'll be building all of
|
||||
# our required methods in Codegen. Generate members now.
|
||||
self.maplikeOrSetlike.expand(self.members, self.isJSImplemented())
|
||||
|
||||
# Now that we've merged in our partial interfaces, set the
|
||||
# _exposureGlobalNames on any members that don't have it set yet. Note
|
||||
# that any partial interfaces that had [Exposed] set have already set up
|
||||
@ -721,7 +743,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
|
||||
if self.parent:
|
||||
self.parent.finish(scope)
|
||||
|
||||
self.parent._hasChildInterfaces = True
|
||||
|
||||
self.totalMembersInSlots = self.parent.totalMembersInSlots
|
||||
@ -839,6 +860,17 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
"consequential interface %s is not exposed." %
|
||||
(self.identifier.name, iface.identifier.name),
|
||||
[self.location, iface.location])
|
||||
|
||||
# If we have a maplike or setlike, and the consequential interface
|
||||
# also does, throw an error.
|
||||
if iface.maplikeOrSetlike and self.maplikeOrSetlike:
|
||||
raise WebIDLError("Maplike/setlike interface %s cannot have "
|
||||
"maplike/setlike interface %s as a "
|
||||
"consequential interface" %
|
||||
(self.identifier.name,
|
||||
iface.identifier.name),
|
||||
[self.maplikeOrSetlike.location,
|
||||
iface.maplikeOrSetlike.location])
|
||||
additionalMembers = iface.originalMembers;
|
||||
for additionalMember in additionalMembers:
|
||||
for member in self.members:
|
||||
@ -852,6 +884,15 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
|
||||
for ancestor in self.getInheritedInterfaces():
|
||||
ancestor.interfacesBasedOnSelf.add(self)
|
||||
if (ancestor.maplikeOrSetlike is not None and
|
||||
self.maplikeOrSetlike is not None):
|
||||
raise WebIDLError("Cannot have maplike/setlike on %s that "
|
||||
"inherits %s, which is already "
|
||||
"maplike/setlike" %
|
||||
(self.identifier.name,
|
||||
ancestor.identifier.name),
|
||||
[self.maplikeOrSetlike.location,
|
||||
ancestor.maplikeOrSetlike.location])
|
||||
for ancestorConsequential in ancestor.getConsequentialInterfaces():
|
||||
ancestorConsequential.interfacesBasedOnSelf.add(self)
|
||||
|
||||
@ -888,12 +929,14 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
not hasattr(member, "originatingInterface")):
|
||||
member.originatingInterface = self
|
||||
|
||||
# Compute slot indices for our members before we pull in
|
||||
# unforgeable members from our parent.
|
||||
# Compute slot indices for our members before we pull in unforgeable
|
||||
# members from our parent. Also, maplike/setlike declarations get a
|
||||
# slot to hold their backing object.
|
||||
for member in self.members:
|
||||
if (member.isAttr() and
|
||||
(member.getExtendedAttribute("StoreInSlot") or
|
||||
member.getExtendedAttribute("Cached"))):
|
||||
if ((member.isAttr() and
|
||||
(member.getExtendedAttribute("StoreInSlot") or
|
||||
member.getExtendedAttribute("Cached"))) or
|
||||
member.isMaplikeOrSetlike()):
|
||||
member.slotIndex = self.totalMembersInSlots
|
||||
self.totalMembersInSlots += 1
|
||||
if member.getExtendedAttribute("StoreInSlot"):
|
||||
@ -930,6 +973,18 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
# complicated and seems unnecessary.
|
||||
self.members.append(unforgeableMember)
|
||||
|
||||
# At this point, we have all of our members. If the current interface
|
||||
# uses maplike/setlike, check for collisions anywhere in the current
|
||||
# interface or higher in the inheritance chain.
|
||||
if self.maplikeOrSetlike:
|
||||
testInterface = self
|
||||
isAncestor = False
|
||||
while testInterface:
|
||||
self.maplikeOrSetlike.checkCollisions(testInterface.members,
|
||||
isAncestor)
|
||||
isAncestor = True
|
||||
testInterface = testInterface.parent
|
||||
|
||||
# Ensure that there's at most one of each {named,indexed}
|
||||
# {getter,setter,creator,deleter}, at most one stringifier,
|
||||
# and at most one legacycaller. Note that this last is not
|
||||
@ -3242,7 +3297,8 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
Tags = enum(
|
||||
'Const',
|
||||
'Attr',
|
||||
'Method'
|
||||
'Method',
|
||||
'MaplikeOrSetlike'
|
||||
)
|
||||
|
||||
Special = enum(
|
||||
@ -3268,6 +3324,9 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
def isConst(self):
|
||||
return self.tag == IDLInterfaceMember.Tags.Const
|
||||
|
||||
def isMaplikeOrSetlike(self):
|
||||
return self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike
|
||||
|
||||
def addExtendedAttributes(self, attrs):
|
||||
for attr in attrs:
|
||||
self.handleExtendedAttribute(attr)
|
||||
@ -3340,6 +3399,256 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
[self.location])
|
||||
self.aliases.append(alias)
|
||||
|
||||
|
||||
# MaplikeOrSetlike adds a trait to an interface, like map or iteration
|
||||
# functions. To handle them while still getting all of the generated binding
|
||||
# code taken care of, we treat them as macros that are expanded into members
|
||||
# based on parsed values.
|
||||
class IDLMaplikeOrSetlike(IDLInterfaceMember):
|
||||
|
||||
MaplikeOrSetlikeTypes = enum(
|
||||
'maplike',
|
||||
'setlike'
|
||||
)
|
||||
|
||||
def __init__(self, location, identifier, maplikeOrSetlikeType,
|
||||
readonly, keyType, valueType):
|
||||
IDLInterfaceMember.__init__(self, location, identifier,
|
||||
IDLInterfaceMember.Tags.MaplikeOrSetlike)
|
||||
|
||||
assert isinstance(keyType, IDLType)
|
||||
assert isinstance(valueType, IDLType)
|
||||
self.maplikeOrSetlikeType = maplikeOrSetlikeType
|
||||
self.readonly = readonly
|
||||
self.keyType = keyType
|
||||
self.valueType = valueType
|
||||
self.slotIndex = None
|
||||
self.disallowedMemberNames = []
|
||||
self.disallowedNonMethodNames = []
|
||||
|
||||
# When generating JSAPI access code, we need to know the backing object
|
||||
# type prefix to create the correct function. Generate here for reuse.
|
||||
if self.isMaplike():
|
||||
self.prefix = 'Map'
|
||||
elif self.isSetlike():
|
||||
self.prefix = 'Set'
|
||||
|
||||
def __str__(self):
|
||||
return "declared '%s' with key '%s'" % (self.maplikeOrSetlikeType, self.keyType)
|
||||
|
||||
def isMaplike(self):
|
||||
return self.maplikeOrSetlikeType == "maplike"
|
||||
|
||||
def isSetlike(self):
|
||||
return self.maplikeOrSetlikeType == "setlike"
|
||||
|
||||
def checkCollisions(self, members, isAncestor):
|
||||
for member in members:
|
||||
# Check that there are no disallowed members
|
||||
if (member.identifier.name in self.disallowedMemberNames and
|
||||
not ((member.isMethod() and member.isMaplikeOrSetlikeMethod()) or
|
||||
(member.isAttr() and member.isMaplikeOrSetlikeAttr()))):
|
||||
raise WebIDLError("Member '%s' conflicts "
|
||||
"with reserved %s name." %
|
||||
(member.identifier.name,
|
||||
self.maplikeOrSetlikeType),
|
||||
[self.location, member.location])
|
||||
# Check that there are no disallowed non-method members
|
||||
if (isAncestor or (member.isAttr() or member.isConst()) and
|
||||
member.identifier.name in self.disallowedNonMethodNames):
|
||||
raise WebIDLError("Member '%s' conflicts "
|
||||
"with reserved %s method." %
|
||||
(member.identifier.name,
|
||||
self.maplikeOrSetlikeType),
|
||||
[self.location, member.location])
|
||||
|
||||
def expand(self, members, isJSImplemented):
|
||||
"""
|
||||
In order to take advantage of all of the method machinery in Codegen,
|
||||
we generate our functions as if they were part of the interface
|
||||
specification during parsing.
|
||||
"""
|
||||
def addMethod(name, allowExistingOperations, returnType, args=[],
|
||||
chromeOnly=False, isPure=False, affectsNothing=False):
|
||||
"""
|
||||
Create an IDLMethod based on the parameters passed in. chromeOnly is only
|
||||
True for read-only js implemented classes, to implement underscore
|
||||
prefixed convenience functions would otherwise not be available,
|
||||
unlike the case of C++ bindings. isPure is only True for
|
||||
idempotent functions, so it is not valid for things like keys,
|
||||
values, etc. that return a new object every time.
|
||||
|
||||
"""
|
||||
|
||||
# Only add name to lists for collision checks if it's not chrome
|
||||
# only.
|
||||
if chromeOnly:
|
||||
name = "__" + name
|
||||
else:
|
||||
if not allowExistingOperations:
|
||||
self.disallowedMemberNames.append(name)
|
||||
else:
|
||||
self.disallowedNonMethodNames.append(name)
|
||||
|
||||
# If allowExistingOperations is True, and another operation exists
|
||||
# with the same name as the one we're trying to add, don't add the
|
||||
# maplike/setlike operation. However, if the operation is static,
|
||||
# then fail by way of creating the function, which will cause a
|
||||
# naming conflict, per the spec.
|
||||
if allowExistingOperations:
|
||||
for m in members:
|
||||
if m.identifier.name == name and m.isMethod() and not m.isStatic():
|
||||
return
|
||||
|
||||
method = IDLMethod(self.location,
|
||||
IDLUnresolvedIdentifier(self.location, name, allowDoubleUnderscore=chromeOnly),
|
||||
returnType, args, maplikeOrSetlike=self)
|
||||
|
||||
# We need to be able to throw from declaration methods
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("Throws",))])
|
||||
if chromeOnly:
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("ChromeOnly",))])
|
||||
if isPure:
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("Pure",))])
|
||||
# Following attributes are used for keys/values/entries. Can't mark
|
||||
# them pure, since they return a new object each time they are run.
|
||||
if affectsNothing:
|
||||
method.addExtendedAttributes(
|
||||
[IDLExtendedAttribute(self.location, ("DependsOn", "Everything")),
|
||||
IDLExtendedAttribute(self.location, ("Affects", "Nothing"))])
|
||||
members.append(method)
|
||||
|
||||
# Both maplike and setlike have a size attribute
|
||||
members.append(IDLAttribute(self.location,
|
||||
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), "size"),
|
||||
BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
|
||||
True,
|
||||
maplikeOrSetlike=self))
|
||||
self.reserved_ro_names = ["size"]
|
||||
|
||||
# object entries()
|
||||
addMethod("entries", False, BuiltinTypes[IDLBuiltinType.Types.object],
|
||||
affectsNothing=True)
|
||||
# object keys()
|
||||
addMethod("keys", False, BuiltinTypes[IDLBuiltinType.Types.object],
|
||||
affectsNothing=True)
|
||||
# object values()
|
||||
addMethod("values", False, BuiltinTypes[IDLBuiltinType.Types.object],
|
||||
affectsNothing=True)
|
||||
|
||||
# void forEach(callback(valueType, keyType), thisVal)
|
||||
foreachArguments = [IDLArgument(self.location,
|
||||
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
|
||||
"callback"),
|
||||
BuiltinTypes[IDLBuiltinType.Types.object]),
|
||||
IDLArgument(self.location,
|
||||
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
|
||||
"thisArg"),
|
||||
BuiltinTypes[IDLBuiltinType.Types.any],
|
||||
optional=True)]
|
||||
addMethod("forEach", False, BuiltinTypes[IDLBuiltinType.Types.void],
|
||||
foreachArguments)
|
||||
|
||||
def getKeyArg():
|
||||
return IDLArgument(self.location,
|
||||
IDLUnresolvedIdentifier(self.location, "key"),
|
||||
self.keyType)
|
||||
|
||||
# boolean has(keyType key)
|
||||
addMethod("has", False, BuiltinTypes[IDLBuiltinType.Types.boolean],
|
||||
[getKeyArg()], isPure=True)
|
||||
|
||||
if not self.readonly:
|
||||
# void clear()
|
||||
addMethod("clear", True, BuiltinTypes[IDLBuiltinType.Types.void],
|
||||
[])
|
||||
# boolean delete(keyType key)
|
||||
addMethod("delete", True,
|
||||
BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()])
|
||||
|
||||
# Always generate underscored functions (e.g. __add, __clear) for js
|
||||
# implemented interfaces as convenience functions.
|
||||
if isJSImplemented:
|
||||
# void clear()
|
||||
addMethod("clear", True, BuiltinTypes[IDLBuiltinType.Types.void],
|
||||
[], chromeOnly=True)
|
||||
# boolean delete(keyType key)
|
||||
addMethod("delete", True,
|
||||
BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()],
|
||||
chromeOnly=True)
|
||||
|
||||
if self.isSetlike():
|
||||
if not self.readonly:
|
||||
# Add returns the set object it just added to.
|
||||
# object add(keyType key)
|
||||
|
||||
addMethod("add", True,
|
||||
BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()])
|
||||
if isJSImplemented:
|
||||
addMethod("add", True,
|
||||
BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()],
|
||||
chromeOnly=True)
|
||||
return
|
||||
|
||||
# If we get this far, we're a maplike declaration.
|
||||
|
||||
# valueType get(keyType key)
|
||||
#
|
||||
# Note that instead of the value type, we're using any here. The
|
||||
# validity checks should happen as things are inserted into the map,
|
||||
# and using any as the return type makes code generation much simpler.
|
||||
#
|
||||
# TODO: Bug 1155340 may change this to use specific type to provide
|
||||
# more info to JIT.
|
||||
addMethod("get", False, BuiltinTypes[IDLBuiltinType.Types.any],
|
||||
[getKeyArg()], isPure=True)
|
||||
|
||||
def getValueArg():
|
||||
return IDLArgument(self.location,
|
||||
IDLUnresolvedIdentifier(self.location, "value"),
|
||||
self.valueType)
|
||||
|
||||
|
||||
if not self.readonly:
|
||||
addMethod("set", True, BuiltinTypes[IDLBuiltinType.Types.object],
|
||||
[getKeyArg(), getValueArg()])
|
||||
if isJSImplemented:
|
||||
addMethod("set", True, BuiltinTypes[IDLBuiltinType.Types.object],
|
||||
[getKeyArg(), getValueArg()], chromeOnly=True)
|
||||
|
||||
def resolve(self, parentScope):
|
||||
self.keyType.resolveType(parentScope)
|
||||
self.valueType.resolveType(parentScope)
|
||||
|
||||
def finish(self, scope):
|
||||
IDLInterfaceMember.finish(self, scope)
|
||||
if not self.keyType.isComplete():
|
||||
t = self.keyType.complete(scope)
|
||||
|
||||
assert not isinstance(t, IDLUnresolvedType)
|
||||
assert not isinstance(t, IDLTypedefType)
|
||||
assert not isinstance(t.name, IDLUnresolvedIdentifier)
|
||||
self.keyType = t
|
||||
if not self.valueType.isComplete():
|
||||
t = self.valueType.complete(scope)
|
||||
|
||||
assert not isinstance(t, IDLUnresolvedType)
|
||||
assert not isinstance(t, IDLTypedefType)
|
||||
assert not isinstance(t.name, IDLUnresolvedIdentifier)
|
||||
self.valueType = t
|
||||
|
||||
def validate(self):
|
||||
IDLInterfaceMember.validate(self)
|
||||
|
||||
def handleExtendedAttribute(self, attr):
|
||||
IDLInterfaceMember.handleExtendedAttribute(self, attr)
|
||||
|
||||
def _getDependentObjects(self):
|
||||
return set([self.keyType, self.valueType])
|
||||
|
||||
class IDLConst(IDLInterfaceMember):
|
||||
def __init__(self, location, identifier, type, value):
|
||||
IDLInterfaceMember.__init__(self, location, identifier,
|
||||
@ -3403,7 +3712,7 @@ class IDLConst(IDLInterfaceMember):
|
||||
|
||||
class IDLAttribute(IDLInterfaceMember):
|
||||
def __init__(self, location, identifier, type, readonly, inherit=False,
|
||||
static=False, stringifier=False):
|
||||
static=False, stringifier=False, maplikeOrSetlike=None):
|
||||
IDLInterfaceMember.__init__(self, location, identifier,
|
||||
IDLInterfaceMember.Tags.Attr)
|
||||
|
||||
@ -3418,6 +3727,8 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
self.enforceRange = False
|
||||
self.clamp = False
|
||||
self.slotIndex = None
|
||||
assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike)
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self.dependsOn = "Everything"
|
||||
self.affects = "Everything"
|
||||
|
||||
@ -3676,6 +3987,14 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
def hasLenientThis(self):
|
||||
return self.lenientThis
|
||||
|
||||
def isMaplikeOrSetlikeAttr(self):
|
||||
"""
|
||||
True if this attribute was generated from an interface with
|
||||
maplike/setlike (e.g. this is the size attribute for
|
||||
maplike/setlike)
|
||||
"""
|
||||
return self.maplikeOrSetlike is not None
|
||||
|
||||
def isUnforgeable(self):
|
||||
return self._unforgeable
|
||||
|
||||
@ -3914,7 +4233,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
def __init__(self, location, identifier, returnType, arguments,
|
||||
static=False, getter=False, setter=False, creator=False,
|
||||
deleter=False, specialType=NamedOrIndexed.Neither,
|
||||
legacycaller=False, stringifier=False, jsonifier=False):
|
||||
legacycaller=False, stringifier=False, jsonifier=False,
|
||||
maplikeOrSetlike=None):
|
||||
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
|
||||
IDLInterfaceMember.__init__(self, location, identifier,
|
||||
IDLInterfaceMember.Tags.Method)
|
||||
@ -3942,6 +4262,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
self._stringifier = stringifier
|
||||
assert isinstance(jsonifier, bool)
|
||||
self._jsonifier = jsonifier
|
||||
assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike)
|
||||
self.maplikeOrSetlike = maplikeOrSetlike
|
||||
self._specialType = specialType
|
||||
self._unforgeable = False
|
||||
self.dependsOn = "Everything"
|
||||
@ -4023,11 +4345,26 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
def isJsonifier(self):
|
||||
return self._jsonifier
|
||||
|
||||
def isMaplikeOrSetlikeMethod(self):
|
||||
"""
|
||||
True if this method was generated as part of a
|
||||
maplike/setlike/etc interface (e.g. has/get methods)
|
||||
"""
|
||||
return self.maplikeOrSetlike is not None
|
||||
|
||||
def hasOverloads(self):
|
||||
return self._hasOverloads
|
||||
|
||||
def isIdentifierLess(self):
|
||||
return self.identifier.name[:2] == "__"
|
||||
"""
|
||||
True if the method name started with __, and if the method is not a
|
||||
maplike/setlike method. Interfaces with maplike/setlike will generate
|
||||
methods starting with __ for chrome only backing object access in JS
|
||||
implemented interfaces, so while these functions use what is considered
|
||||
an non-identifier name, they actually DO have an identifier.
|
||||
"""
|
||||
return (self.identifier.name[:2] == "__" and
|
||||
not self.isMaplikeOrSetlikeMethod())
|
||||
|
||||
def resolve(self, parentScope):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
@ -4517,7 +4854,9 @@ class Tokenizer(object):
|
||||
">": "GT",
|
||||
"ArrayBuffer": "ARRAYBUFFER",
|
||||
"SharedArrayBuffer": "SHAREDARRAYBUFFER",
|
||||
"or": "OR"
|
||||
"or": "OR",
|
||||
"maplike": "MAPLIKE",
|
||||
"setlike": "SETLIKE"
|
||||
}
|
||||
|
||||
tokens.extend(keywords.values())
|
||||
@ -4753,7 +5092,7 @@ class Parser(Tokenizer):
|
||||
def p_InterfaceMember(self, p):
|
||||
"""
|
||||
InterfaceMember : Const
|
||||
| AttributeOrOperation
|
||||
| AttributeOrOperationOrMaplikeOrSetlike
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
@ -4968,13 +5307,43 @@ class Parser(Tokenizer):
|
||||
"""
|
||||
p[0] = False
|
||||
|
||||
def p_AttributeOrOperation(self, p):
|
||||
def p_AttributeOrOperationOrMaplikeOrSetlike(self, p):
|
||||
"""
|
||||
AttributeOrOperation : Attribute
|
||||
| Operation
|
||||
AttributeOrOperationOrMaplikeOrSetlike : Attribute
|
||||
| Maplike
|
||||
| Setlike
|
||||
| Operation
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_Setlike(self, p):
|
||||
"""
|
||||
Setlike : ReadOnly SETLIKE LT Type GT SEMICOLON
|
||||
"""
|
||||
readonly = p[1]
|
||||
maplikeOrSetlikeType = p[2]
|
||||
location = self.getLocation(p, 2)
|
||||
identifier = IDLUnresolvedIdentifier(location, "__setlike",
|
||||
allowDoubleUnderscore=True)
|
||||
keyType = p[4]
|
||||
valueType = keyType
|
||||
p[0] = IDLMaplikeOrSetlike(location, identifier, maplikeOrSetlikeType,
|
||||
readonly, keyType, valueType)
|
||||
|
||||
def p_Maplike(self, p):
|
||||
"""
|
||||
Maplike : ReadOnly MAPLIKE LT Type COMMA Type GT SEMICOLON
|
||||
"""
|
||||
readonly = p[1]
|
||||
maplikeOrSetlikeType = p[2]
|
||||
location = self.getLocation(p, 2)
|
||||
identifier = IDLUnresolvedIdentifier(location, "__maplike",
|
||||
allowDoubleUnderscore=True)
|
||||
keyType = p[4]
|
||||
valueType = p[6]
|
||||
p[0] = IDLMaplikeOrSetlike(location, identifier, maplikeOrSetlikeType,
|
||||
readonly, keyType, valueType)
|
||||
|
||||
def p_AttributeWithQualifier(self, p):
|
||||
"""
|
||||
Attribute : Qualifier AttributeRest
|
||||
@ -4982,15 +5351,22 @@ class Parser(Tokenizer):
|
||||
static = IDLInterfaceMember.Special.Static in p[1]
|
||||
stringifier = IDLInterfaceMember.Special.Stringifier in p[1]
|
||||
(location, identifier, type, readonly) = p[2]
|
||||
p[0] = IDLAttribute(location, identifier, type, readonly, static=static,
|
||||
stringifier=stringifier)
|
||||
p[0] = IDLAttribute(location, identifier, type, readonly,
|
||||
static=static, stringifier=stringifier)
|
||||
|
||||
def p_AttributeInherited(self, p):
|
||||
"""
|
||||
Attribute : INHERIT AttributeRest
|
||||
"""
|
||||
(location, identifier, type, readonly) = p[2]
|
||||
p[0] = IDLAttribute(location, identifier, type, readonly, inherit=True)
|
||||
|
||||
def p_Attribute(self, p):
|
||||
"""
|
||||
Attribute : Inherit AttributeRest
|
||||
Attribute : AttributeRest
|
||||
"""
|
||||
(location, identifier, type, readonly) = p[2]
|
||||
p[0] = IDLAttribute(location, identifier, type, readonly, inherit=p[1])
|
||||
(location, identifier, type, readonly) = p[1]
|
||||
p[0] = IDLAttribute(location, identifier, type, readonly, inherit=False)
|
||||
|
||||
def p_AttributeRest(self, p):
|
||||
"""
|
||||
@ -5014,18 +5390,6 @@ class Parser(Tokenizer):
|
||||
"""
|
||||
p[0] = False
|
||||
|
||||
def p_Inherit(self, p):
|
||||
"""
|
||||
Inherit : INHERIT
|
||||
"""
|
||||
p[0] = True
|
||||
|
||||
def p_InheritEmpty(self, p):
|
||||
"""
|
||||
Inherit :
|
||||
"""
|
||||
p[0] = False
|
||||
|
||||
def p_Operation(self, p):
|
||||
"""
|
||||
Operation : Qualifiers OperationRest
|
||||
@ -5322,9 +5686,11 @@ class Parser(Tokenizer):
|
||||
| INHERIT
|
||||
| INTERFACE
|
||||
| LEGACYCALLER
|
||||
| MAPLIKE
|
||||
| PARTIAL
|
||||
| REQUIRED
|
||||
| SERIALIZER
|
||||
| SETLIKE
|
||||
| SETTER
|
||||
| STATIC
|
||||
| STRINGIFIER
|
||||
|
528
dom/bindings/parser/tests/test_interface_maplikesetlike.py
Normal file
528
dom/bindings/parser/tests/test_interface_maplikesetlike.py
Normal file
@ -0,0 +1,528 @@
|
||||
import WebIDL
|
||||
import traceback
|
||||
def WebIDLTest(parser, harness):
|
||||
|
||||
def shouldPass(prefix, iface, expectedMembers, numProductions=1):
|
||||
p = parser.reset()
|
||||
p.parse(iface)
|
||||
results = p.finish()
|
||||
harness.check(len(results), numProductions,
|
||||
"%s - Should have production count %d" % (prefix, numProductions))
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterface),
|
||||
"%s - Should be an IDLInterface" % (prefix))
|
||||
harness.check(len(results[0].members), len(expectedMembers),
|
||||
"%s - Should be %d members" % (prefix,
|
||||
len(expectedMembers)))
|
||||
for m in results[0].members:
|
||||
name = m.identifier.name
|
||||
if (name, type(m)) in expectedMembers:
|
||||
harness.ok(True, "%s - %s - Should be a %s" % (prefix, name,
|
||||
type(m)))
|
||||
elif isinstance(m, WebIDL.IDLMaplikeOrSetlike):
|
||||
harness.ok(True, "%s - %s - Should be a MaplikeOrSetlike" %
|
||||
(prefix, name))
|
||||
else:
|
||||
harness.ok(False, "%s - %s - Unknown symbol of type %s" %
|
||||
(prefix, name, type(m)))
|
||||
return results
|
||||
|
||||
def shouldFail(prefix, iface):
|
||||
try:
|
||||
p = parser.reset()
|
||||
p.parse(iface)
|
||||
p.finish()
|
||||
harness.ok(False,
|
||||
prefix + " - Interface passed when should've failed")
|
||||
except WebIDL.WebIDLError, e:
|
||||
harness.ok(True,
|
||||
prefix + " - Interface failed as expected")
|
||||
except Exception, e:
|
||||
harness.ok(False,
|
||||
prefix + " - Interface failed but not as a WebIDLError exception")
|
||||
|
||||
iterableMembers = [(x, WebIDL.IDLMethod) for x in ["entries", "keys",
|
||||
"values", "forEach"]]
|
||||
iterableMembers.extend([("size", WebIDL.IDLAttribute)])
|
||||
setROMembers = ([(x, WebIDL.IDLMethod) for x in ["has"]] +
|
||||
[("__setlike", WebIDL.IDLMaplikeOrSetlike)] +
|
||||
iterableMembers)
|
||||
setRWMembers = ([(x, WebIDL.IDLMethod) for x in ["add",
|
||||
"clear",
|
||||
"delete"]] +
|
||||
setROMembers)
|
||||
setROChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__add",
|
||||
"__clear",
|
||||
"__delete"]] +
|
||||
setROMembers)
|
||||
setRWChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__add",
|
||||
"__clear",
|
||||
"__delete"]] +
|
||||
setRWMembers)
|
||||
mapROMembers = ([(x, WebIDL.IDLMethod) for x in ["get", "has"]] +
|
||||
[("__maplike", WebIDL.IDLMaplikeOrSetlike)] +
|
||||
iterableMembers)
|
||||
mapRWMembers = ([(x, WebIDL.IDLMethod) for x in ["set",
|
||||
"clear",
|
||||
"delete"]] + mapROMembers)
|
||||
mapRWChromeMembers = ([(x, WebIDL.IDLMethod) for x in ["__set",
|
||||
"__clear",
|
||||
"__delete"]] +
|
||||
mapRWMembers)
|
||||
|
||||
disallowedMemberNames = ["keys", "entries", "values", "forEach", "has",
|
||||
"size"]
|
||||
mapDisallowedMemberNames = ["get"] + disallowedMemberNames
|
||||
disallowedNonMethodNames = ["clear", "delete"]
|
||||
mapDisallowedNonMethodNames = ["set"] + disallowedNonMethodNames
|
||||
setDisallowedNonMethodNames = ["add"] + disallowedNonMethodNames
|
||||
|
||||
#
|
||||
# Simple Usage Tests
|
||||
#
|
||||
|
||||
shouldPass("Maplike (readwrite)",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""", mapRWMembers)
|
||||
|
||||
shouldPass("Maplike (readonly)",
|
||||
"""
|
||||
interface Foo1 {
|
||||
readonly maplike<long, long>;
|
||||
};
|
||||
""", mapROMembers)
|
||||
|
||||
shouldPass("Setlike (readwrite)",
|
||||
"""
|
||||
interface Foo1 {
|
||||
setlike<long>;
|
||||
};
|
||||
""", setRWMembers)
|
||||
|
||||
shouldPass("Setlike (readonly)",
|
||||
"""
|
||||
interface Foo1 {
|
||||
readonly setlike<long>;
|
||||
};
|
||||
""", setROMembers)
|
||||
|
||||
shouldPass("Inheritance of maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
""", mapRWMembers, numProductions=2)
|
||||
|
||||
shouldPass("Implements with maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 {
|
||||
};
|
||||
Foo2 implements Foo1;
|
||||
""", mapRWMembers, numProductions=3)
|
||||
|
||||
shouldPass("JS Implemented maplike interface",
|
||||
"""
|
||||
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1",
|
||||
Constructor()]
|
||||
interface Foo1 {
|
||||
setlike<long>;
|
||||
};
|
||||
""", setRWChromeMembers)
|
||||
|
||||
shouldPass("JS Implemented maplike interface",
|
||||
"""
|
||||
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1",
|
||||
Constructor()]
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""", mapRWChromeMembers)
|
||||
|
||||
#
|
||||
# Multiple maplike/setlike tests
|
||||
#
|
||||
|
||||
shouldFail("Two maplike/setlikes on same interface",
|
||||
"""
|
||||
interface Foo1 {
|
||||
setlike<long>;
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Two maplike/setlikes in partials",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
partial interface Foo1 {
|
||||
setlike<long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Conflicting maplike/setlikes across inheritance",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
setlike<long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Conflicting maplike/setlikes across multistep inheritance",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
setlike<long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Consequential interface with conflicting maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 {
|
||||
setlike<long>;
|
||||
};
|
||||
Foo2 implements Foo1;
|
||||
""")
|
||||
|
||||
shouldFail("Consequential interfaces with conflicting maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 {
|
||||
setlike<long>;
|
||||
};
|
||||
interface Foo3 {
|
||||
};
|
||||
Foo3 implements Foo1;
|
||||
Foo3 implements Foo2;
|
||||
""")
|
||||
|
||||
#
|
||||
# Member name collision tests
|
||||
#
|
||||
|
||||
def testConflictingMembers(likeMember, conflictName, expectedMembers, methodPasses):
|
||||
"""
|
||||
Tests for maplike/setlike member generation against conflicting member
|
||||
names. If methodPasses is True, this means we expect the interface to
|
||||
pass in the case of method shadowing, and expectedMembers should be the
|
||||
list of interface members to check against on the passing interface.
|
||||
|
||||
"""
|
||||
if methodPasses:
|
||||
shouldPass("Conflicting method: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
%s;
|
||||
[Throws]
|
||||
void %s(long test1, double test2, double test3);
|
||||
};
|
||||
""" % (likeMember, conflictName), expectedMembers)
|
||||
else:
|
||||
shouldFail("Conflicting method: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
%s;
|
||||
[Throws]
|
||||
void %s(long test1, double test2, double test3);
|
||||
};
|
||||
""" % (likeMember, conflictName))
|
||||
# Inherited conflicting methods should ALWAYS fail
|
||||
shouldFail("Conflicting inherited method: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
void %s(long test1, double test2, double test3);
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
%s;
|
||||
};
|
||||
""" % (conflictName, likeMember))
|
||||
shouldFail("Conflicting static method: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
%s;
|
||||
static void %s(long test1, double test2, double test3);
|
||||
};
|
||||
""" % (likeMember, conflictName))
|
||||
shouldFail("Conflicting attribute: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
%s
|
||||
attribute double %s;
|
||||
};
|
||||
""" % (likeMember, conflictName))
|
||||
shouldFail("Conflicting const: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
%s;
|
||||
const double %s = 0;
|
||||
};
|
||||
""" % (likeMember, conflictName))
|
||||
shouldFail("Conflicting static attribute: %s and %s" % (likeMember, conflictName),
|
||||
"""
|
||||
interface Foo1 {
|
||||
%s;
|
||||
static attribute long %s;
|
||||
};
|
||||
""" % (likeMember, conflictName))
|
||||
|
||||
for member in mapDisallowedMemberNames:
|
||||
testConflictingMembers("maplike<long, long>", member, mapRWMembers, False)
|
||||
for member in disallowedMemberNames:
|
||||
testConflictingMembers("setlike<long>", member, setRWMembers, False)
|
||||
for member in mapDisallowedNonMethodNames:
|
||||
testConflictingMembers("maplike<long, long>", member, mapRWMembers, True)
|
||||
for member in setDisallowedNonMethodNames:
|
||||
testConflictingMembers("setlike<long>", member, setRWMembers, True)
|
||||
|
||||
shouldPass("Inheritance of maplike/setlike with child member collision",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
void entries();
|
||||
};
|
||||
""", mapRWMembers, numProductions=2)
|
||||
|
||||
shouldPass("Inheritance of multi-level maplike/setlike with child member collision",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
void entries();
|
||||
};
|
||||
""", mapRWMembers, numProductions=3)
|
||||
|
||||
shouldFail("Interface with consequential maplike/setlike interface member collision",
|
||||
"""
|
||||
interface Foo1 {
|
||||
void entries();
|
||||
};
|
||||
interface Foo2 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
Foo1 implements Foo2;
|
||||
""")
|
||||
|
||||
shouldFail("Maplike interface with consequential interface member collision",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 {
|
||||
void entries();
|
||||
};
|
||||
Foo1 implements Foo2;
|
||||
""")
|
||||
|
||||
shouldPass("Consequential Maplike interface with inherited interface member collision",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 {
|
||||
void entries();
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
};
|
||||
Foo3 implements Foo1;
|
||||
""", mapRWMembers, numProductions=4)
|
||||
|
||||
shouldPass("Inherited Maplike interface with consequential interface member collision",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 {
|
||||
void entries();
|
||||
};
|
||||
interface Foo3 : Foo1 {
|
||||
};
|
||||
Foo3 implements Foo2;
|
||||
""", mapRWMembers, numProductions=4)
|
||||
|
||||
shouldFail("Inheritance of name collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
void entries();
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Inheritance of multi-level name collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
void entries();
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldPass("Inheritance of attribute collision with parent maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
attribute double size;
|
||||
};
|
||||
""", mapRWMembers, numProductions=2)
|
||||
|
||||
shouldPass("Inheritance of multi-level attribute collision with parent maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
attribute double size;
|
||||
};
|
||||
""", mapRWMembers, numProductions=3)
|
||||
|
||||
shouldFail("Inheritance of attribute collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
attribute double size;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Inheritance of multi-level attribute collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
attribute double size;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Inheritance of attribute/rw function collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
attribute double set;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Inheritance of const/rw function collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
const double set = 0;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldPass("Inheritance of rw function with same name in child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
void clear();
|
||||
};
|
||||
""", mapRWMembers, numProductions=2)
|
||||
|
||||
shouldFail("Inheritance of unforgeable attribute collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
[Unforgeable]
|
||||
attribute double size;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldFail("Inheritance of multi-level unforgeable attribute collision with child maplike/setlike",
|
||||
"""
|
||||
interface Foo1 {
|
||||
[Unforgeable]
|
||||
attribute double size;
|
||||
};
|
||||
interface Foo2 : Foo1 {
|
||||
};
|
||||
interface Foo3 : Foo2 {
|
||||
maplike<long, long>;
|
||||
};
|
||||
""")
|
||||
|
||||
shouldPass("Implemented interface with readonly allowable overrides",
|
||||
"""
|
||||
interface Foo1 {
|
||||
readonly setlike<long>;
|
||||
readonly attribute boolean clear;
|
||||
};
|
||||
""", setROMembers + [("clear", WebIDL.IDLAttribute)])
|
||||
|
||||
shouldPass("JS Implemented read-only interface with readonly allowable overrides",
|
||||
"""
|
||||
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1",
|
||||
Constructor()]
|
||||
interface Foo1 {
|
||||
readonly setlike<long>;
|
||||
readonly attribute boolean clear;
|
||||
};
|
||||
""", setROChromeMembers + [("clear", WebIDL.IDLAttribute)])
|
||||
|
||||
shouldFail("JS Implemented read-write interface with non-readwrite allowable overrides",
|
||||
"""
|
||||
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1",
|
||||
Constructor()]
|
||||
interface Foo1 {
|
||||
setlike<long>;
|
||||
readonly attribute boolean clear;
|
||||
};
|
||||
""")
|
||||
|
||||
r = shouldPass("Check proper override of clear/delete/set",
|
||||
"""
|
||||
interface Foo1 {
|
||||
maplike<long, long>;
|
||||
long clear(long a, long b, double c, double d);
|
||||
long set(long a, long b, double c, double d);
|
||||
long delete(long a, long b, double c, double d);
|
||||
};
|
||||
""", mapRWMembers)
|
||||
|
||||
for m in r[0].members:
|
||||
if m.identifier.name in ["clear", "set", "delete"]:
|
||||
harness.ok(m.isMethod(), "%s should be a method" % m.identifier.name)
|
||||
harness.check(m.maxArgCount, 4, "%s should have 4 arguments" % m.identifier.name)
|
||||
harness.ok(not m.isMaplikeOrSetlikeMethod(),
|
||||
"%s should not be a maplike/setlike function" % m.identifier.name)
|
@ -1,2 +1,4 @@
|
||||
component {2ac4e026-cf25-47d5-b067-78d553c3cad8} TestInterfaceJS.js
|
||||
contract @mozilla.org/dom/test-interface-js;1 {2ac4e026-cf25-47d5-b067-78d553c3cad8}
|
||||
component {4bc6f6f3-e005-4f0a-b42d-4d1663a9013a} TestInterfaceJSMaplike.js
|
||||
contract @mozilla.org/dom/test-interface-js-maplike;1 {4bc6f6f3-e005-4f0a-b42d-4d1663a9013a}
|
||||
|
38
dom/bindings/test/TestInterfaceJSMaplike.js
Normal file
38
dom/bindings/test/TestInterfaceJSMaplike.js
Normal file
@ -0,0 +1,38 @@
|
||||
/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function TestInterfaceJSMaplike() {}
|
||||
|
||||
TestInterfaceJSMaplike.prototype = {
|
||||
classID: Components.ID("{4bc6f6f3-e005-4f0a-b42d-4d1663a9013a}"),
|
||||
contractID: "@mozilla.org/dom/test-interface-js-maplike;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
init: function(win) { this._win = win; },
|
||||
|
||||
__init: function () {},
|
||||
|
||||
setInternal: function(aKey, aValue) {
|
||||
return this.__DOM_IMPL__.__set(aKey, aValue);
|
||||
},
|
||||
|
||||
deleteInternal: function(aKey) {
|
||||
return this.__DOM_IMPL__.__delete(aKey);
|
||||
},
|
||||
|
||||
clearInternal: function() {
|
||||
return this.__DOM_IMPL__.__clear();
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJSMaplike])
|
84
dom/bindings/test/TestInterfaceMaplike.cpp
Normal file
84
dom/bindings/test/TestInterfaceMaplike.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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 "mozilla/dom/TestInterfaceMaplike.h"
|
||||
#include "mozilla/dom/TestInterfaceJSMaplikeSetlikeBinding.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TestInterfaceMaplike, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(TestInterfaceMaplike)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(TestInterfaceMaplike)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TestInterfaceMaplike)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
TestInterfaceMaplike::TestInterfaceMaplike(nsPIDOMWindow* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
already_AddRefed<TestInterfaceMaplike>
|
||||
TestInterfaceMaplike::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<TestInterfaceMaplike> r = new TestInterfaceMaplike(window);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
TestInterfaceMaplike::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return TestInterfaceMaplikeBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
TestInterfaceMaplike::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void
|
||||
TestInterfaceMaplike::SetInternal(const nsAString& aKey, int32_t aValue)
|
||||
{
|
||||
ErrorResult rv;
|
||||
TestInterfaceMaplikeBinding::MaplikeHelpers::Set(this, aKey, aValue, rv);
|
||||
}
|
||||
|
||||
void
|
||||
TestInterfaceMaplike::ClearInternal()
|
||||
{
|
||||
ErrorResult rv;
|
||||
TestInterfaceMaplikeBinding::MaplikeHelpers::Clear(this, rv);
|
||||
}
|
||||
|
||||
bool
|
||||
TestInterfaceMaplike::DeleteInternal(const nsAString& aKey)
|
||||
{
|
||||
ErrorResult rv;
|
||||
return TestInterfaceMaplikeBinding::MaplikeHelpers::Delete(this, aKey, rv);
|
||||
}
|
||||
|
||||
bool
|
||||
TestInterfaceMaplike::HasInternal(const nsAString& aKey)
|
||||
{
|
||||
ErrorResult rv;
|
||||
return TestInterfaceMaplikeBinding::MaplikeHelpers::Has(this, aKey, rv);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
52
dom/bindings/test/TestInterfaceMaplike.h
Normal file
52
dom/bindings/test/TestInterfaceMaplike.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TestInterfaceMaplike_h
|
||||
#define mozilla_dom_TestInterfaceMaplike_h
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
// Implementation of test binding for webidl maplike interfaces, using
|
||||
// primitives for key and value types.
|
||||
class TestInterfaceMaplike final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestInterfaceMaplike)
|
||||
|
||||
explicit TestInterfaceMaplike(nsPIDOMWindow* aParent);
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
static already_AddRefed<TestInterfaceMaplike>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
|
||||
|
||||
// External access for testing internal convenience functions.
|
||||
void SetInternal(const nsAString& aKey, int32_t aValue);
|
||||
void ClearInternal();
|
||||
bool DeleteInternal(const nsAString& aKey);
|
||||
bool HasInternal(const nsAString& aKey);
|
||||
private:
|
||||
virtual ~TestInterfaceMaplike() {}
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_TestInterfaceMaplike_h
|
88
dom/bindings/test/TestInterfaceMaplikeObject.cpp
Normal file
88
dom/bindings/test/TestInterfaceMaplikeObject.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/* 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 "mozilla/dom/TestInterfaceMaplikeObject.h"
|
||||
#include "mozilla/dom/TestInterfaceMaplike.h"
|
||||
#include "mozilla/dom/TestInterfaceJSMaplikeSetlikeBinding.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TestInterfaceMaplikeObject, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(TestInterfaceMaplikeObject)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(TestInterfaceMaplikeObject)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TestInterfaceMaplikeObject)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
TestInterfaceMaplikeObject::TestInterfaceMaplikeObject(nsPIDOMWindow* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
already_AddRefed<TestInterfaceMaplikeObject>
|
||||
TestInterfaceMaplikeObject::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<TestInterfaceMaplikeObject> r =
|
||||
new TestInterfaceMaplikeObject(window);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
TestInterfaceMaplikeObject::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return TestInterfaceMaplikeObjectBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
TestInterfaceMaplikeObject::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void
|
||||
TestInterfaceMaplikeObject::SetInternal(const nsAString& aKey)
|
||||
{
|
||||
nsRefPtr<TestInterfaceMaplike> p(new TestInterfaceMaplike(mParent));
|
||||
ErrorResult rv;
|
||||
TestInterfaceMaplikeObjectBinding::MaplikeHelpers::Set(this, aKey, *p, rv);
|
||||
}
|
||||
|
||||
void
|
||||
TestInterfaceMaplikeObject::ClearInternal()
|
||||
{
|
||||
ErrorResult rv;
|
||||
TestInterfaceMaplikeObjectBinding::MaplikeHelpers::Clear(this, rv);
|
||||
}
|
||||
|
||||
bool
|
||||
TestInterfaceMaplikeObject::DeleteInternal(const nsAString& aKey)
|
||||
{
|
||||
ErrorResult rv;
|
||||
return TestInterfaceMaplikeObjectBinding::MaplikeHelpers::Delete(this, aKey, rv);
|
||||
}
|
||||
|
||||
bool
|
||||
TestInterfaceMaplikeObject::HasInternal(const nsAString& aKey)
|
||||
{
|
||||
ErrorResult rv;
|
||||
return TestInterfaceMaplikeObjectBinding::MaplikeHelpers::Has(this, aKey, rv);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
52
dom/bindings/test/TestInterfaceMaplikeObject.h
Normal file
52
dom/bindings/test/TestInterfaceMaplikeObject.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TestInterfaceMaplikeObject_h
|
||||
#define mozilla_dom_TestInterfaceMaplikeObject_h
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
// Implementation of test binding for webidl maplike interfaces, using
|
||||
// primitives for key types and objects for value types.
|
||||
class TestInterfaceMaplikeObject final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestInterfaceMaplikeObject)
|
||||
|
||||
explicit TestInterfaceMaplikeObject(nsPIDOMWindow* aParent);
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
static already_AddRefed<TestInterfaceMaplikeObject>
|
||||
Constructor(const GlobalObject& aGlobal,ErrorResult& rv);
|
||||
|
||||
// External access for testing internal convenience functions.
|
||||
void SetInternal(const nsAString& aKey);
|
||||
void ClearInternal();
|
||||
bool DeleteInternal(const nsAString& aKey);
|
||||
bool HasInternal(const nsAString& aKey);
|
||||
private:
|
||||
virtual ~TestInterfaceMaplikeObject() {}
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_TestInterfaceMaplikeObject_h
|
58
dom/bindings/test/TestInterfaceSetlike.cpp
Normal file
58
dom/bindings/test/TestInterfaceSetlike.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* 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 "mozilla/dom/TestInterfaceSetlike.h"
|
||||
#include "mozilla/dom/TestInterfaceJSMaplikeSetlikeBinding.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TestInterfaceSetlike, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(TestInterfaceSetlike)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(TestInterfaceSetlike)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TestInterfaceSetlike)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
TestInterfaceSetlike::TestInterfaceSetlike(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
already_AddRefed<TestInterfaceSetlike>
|
||||
TestInterfaceSetlike::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<TestInterfaceSetlike> r = new TestInterfaceSetlike(nullptr, window);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
TestInterfaceSetlike::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return TestInterfaceSetlikeBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
TestInterfaceSetlike::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
46
dom/bindings/test/TestInterfaceSetlike.h
Normal file
46
dom/bindings/test/TestInterfaceSetlike.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TestInterfaceSetlike_h
|
||||
#define mozilla_dom_TestInterfaceSetlike_h
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
// Implementation of test binding for webidl setlike interfaces, using
|
||||
// primitives for key type.
|
||||
class TestInterfaceSetlike final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestInterfaceSetlike)
|
||||
explicit TestInterfaceSetlike(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent);
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
static already_AddRefed<TestInterfaceSetlike>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
|
||||
private:
|
||||
virtual ~TestInterfaceSetlike() {}
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_TestInterfaceSetlike_h
|
58
dom/bindings/test/TestInterfaceSetlikeNode.cpp
Normal file
58
dom/bindings/test/TestInterfaceSetlikeNode.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/* 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 "mozilla/dom/TestInterfaceSetlikeNode.h"
|
||||
#include "mozilla/dom/TestInterfaceJSMaplikeSetlikeBinding.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TestInterfaceSetlikeNode, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(TestInterfaceSetlikeNode)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(TestInterfaceSetlikeNode)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TestInterfaceSetlikeNode)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
TestInterfaceSetlikeNode::TestInterfaceSetlikeNode(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
already_AddRefed<TestInterfaceSetlikeNode>
|
||||
TestInterfaceSetlikeNode::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<TestInterfaceSetlikeNode> r = new TestInterfaceSetlikeNode(nullptr, window);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
TestInterfaceSetlikeNode::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return TestInterfaceSetlikeNodeBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
TestInterfaceSetlikeNode::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
46
dom/bindings/test/TestInterfaceSetlikeNode.h
Normal file
46
dom/bindings/test/TestInterfaceSetlikeNode.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TestInterfaceSetlikeNode_h
|
||||
#define mozilla_dom_TestInterfaceSetlikeNode_h
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
// Implementation of test binding for webidl setlike interfaces, using
|
||||
// primitives for key type.
|
||||
class TestInterfaceSetlikeNode final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TestInterfaceSetlikeNode)
|
||||
explicit TestInterfaceSetlikeNode(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent);
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
static already_AddRefed<TestInterfaceSetlikeNode>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
|
||||
private:
|
||||
virtual ~TestInterfaceSetlikeNode() {}
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_TestInterfaceSetlikeNode_h
|
@ -14,3 +14,5 @@ support-files =
|
||||
skip-if = e10s # prerendering doesn't work in e10s yet
|
||||
[test_kill_longrunning_prerendered_content.xul]
|
||||
skip-if = e10s # prerendering doesn't work in e10s yet
|
||||
[test_bug1123516_maplikesetlikechrome.xul]
|
||||
skip-if = debug == false
|
||||
|
@ -61,3 +61,5 @@ skip-if = debug == false
|
||||
[test_worker_UnwrapArg.html]
|
||||
[test_unforgeablesonexpando.html]
|
||||
[test_crossOriginWindowSymbolAccess.html]
|
||||
[test_bug1123516_maplikesetlike.html]
|
||||
skip-if = debug == false
|
@ -17,6 +17,7 @@ Library('dombindings_test_s')
|
||||
EXTRA_COMPONENTS += [
|
||||
'TestInterfaceJS.js',
|
||||
'TestInterfaceJS.manifest',
|
||||
'TestInterfaceJSMaplike.js'
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
|
270
dom/bindings/test/test_bug1123516_maplikesetlike.html
Normal file
270
dom/bindings/test/test_bug1123516_maplikesetlike.html
Normal file
@ -0,0 +1,270 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Maplike Interface</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
|
||||
|
||||
base_properties = [["has", "function", 1],
|
||||
["entries", "function", 0],
|
||||
["keys", "function", 0],
|
||||
["values", "function", 0],
|
||||
["forEach", "function", 1],
|
||||
["size", "number"]];
|
||||
maplike_properties = base_properties.concat([["set", "function", 2]]);
|
||||
setlike_properties = base_properties;
|
||||
rw_properties = [["clear", "function", 0],
|
||||
["delete", "function", 1]];
|
||||
setlike_rw_properties = base_properties.concat(rw_properties).concat([["add", "function", 1]]);
|
||||
maplike_rw_properties = maplike_properties.concat(rw_properties).concat([["get", "function",1]]);
|
||||
var testExistence = function testExistence(prefix, obj, properties) {
|
||||
for (var [name, type, args] of properties) {
|
||||
// Properties are somewhere up the proto chain, hasOwnProperty won't work
|
||||
isnot(obj[name], undefined,
|
||||
`${prefix} object has property ${name}`);
|
||||
|
||||
is(typeof obj[name], type,
|
||||
`${prefix} object property ${name} is a ${type}`);
|
||||
// Check function length
|
||||
if (type == "function") {
|
||||
is(obj[name].length, args,
|
||||
`${prefix} object property ${name} is length ${args}`);
|
||||
is(obj[name].name, name,
|
||||
`${prefix} object method name is ${name}`);
|
||||
}
|
||||
|
||||
// Find where property is on proto chain, check for enumerablility there.
|
||||
var owner = obj;
|
||||
while (owner) {
|
||||
var propDesc = Object.getOwnPropertyDescriptor(owner, name);
|
||||
if (propDesc) {
|
||||
ok(!propDesc.enumerable,
|
||||
`${prefix} object property ${name} is not enumerable`);
|
||||
break;
|
||||
}
|
||||
owner = Object.getPrototypeOf(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var m;
|
||||
var testSet;
|
||||
var testIndex;
|
||||
var iterable;
|
||||
// Simple map creation and functionality test
|
||||
info("SimpleMap: Testing simple map creation and functionality");
|
||||
m = new TestInterfaceMaplike();
|
||||
ok(m, "SimpleMap: got a TestInterfaceMaplike object");
|
||||
testExistence("SimpleMap: ", m, maplike_rw_properties);
|
||||
is(m.size, 0, "SimpleMap: size should be zero");
|
||||
ok(!m.has("test"), "SimpleMap: maplike has should return false");
|
||||
is(m.get("test"), undefined, "SimpleMap: maplike get should return undefined on bogus lookup");
|
||||
m1 = m.set("test", 1);
|
||||
is(m, m1, "SimpleMap: return from set should be map object");
|
||||
is(m.size, 1, "SimpleMap: size should be 1");
|
||||
ok(m.has("test"), "SimpleMap: maplike has should return true");
|
||||
is(m.get("test"), 1, "SimpleMap: maplike get should return value entered");
|
||||
m2 = m.set("test2", 2);
|
||||
is(m.size, 2, "SimpleMap: size should be 2");
|
||||
testSet = [["test", 1], ["test2", 2]];
|
||||
testIndex = 0;
|
||||
m.forEach(function(v, k, o) {
|
||||
"use strict";
|
||||
is(o, m, "SimpleMap: foreach obj is correct");
|
||||
is(k, testSet[testIndex][0], "SimpleMap: foreach map key: " + k + " = " + testSet[testIndex][0]);
|
||||
is(v, testSet[testIndex][1], "SimpleMap: foreach map value: " + v + " = " + testSet[testIndex][1]);
|
||||
testIndex += 1;
|
||||
});
|
||||
is(testIndex, 2, "SimpleMap: foreach ran correct number of times");
|
||||
ok(m.has("test2"), "SimpleMap: maplike has should return true");
|
||||
is(m.get("test2"), 2, "SimpleMap: maplike get should return value entered");
|
||||
is(m.delete("test2"), true, "SimpleMap: maplike deletion should return boolean");
|
||||
is(m.size, 1, "SimpleMap: size should be 1");
|
||||
iterable = false;
|
||||
for (var e of m) {
|
||||
iterable = true;
|
||||
is(e[0], "test", "SimpleMap: iterable first array element should be key");
|
||||
is(e[1], 1, "SimpleMap: iterable second array element should be value");
|
||||
}
|
||||
is(m[Symbol.iterator].length, 0, "SimpleMap: @@iterator symbol is correct length");
|
||||
is(m[Symbol.iterator].name, "[Symbol.iterator]", "SimpleMap: @@iterator symbol has correct name");
|
||||
ok(iterable, "SimpleMap: @@iterator symbol resolved correctly");
|
||||
for (var k of m.keys()) {
|
||||
is(k, "test", "SimpleMap: first keys element should be 'test'");
|
||||
}
|
||||
for (var v of m.values()) {
|
||||
is(v, 1, "SimpleMap: first values elements should be 1");
|
||||
}
|
||||
for (var e of m.entries()) {
|
||||
is(e[0], "test", "SimpleMap: entries first array element should be 'test'");
|
||||
is(e[1], 1, "SimpleMap: entries second array element should be 1");
|
||||
}
|
||||
m.clear();
|
||||
is(m.size, 0, "SimpleMap: size should be 0 after clear");
|
||||
|
||||
// Simple set creation and functionality test
|
||||
info("SimpleSet: Testing simple set creation and functionality");
|
||||
m = new TestInterfaceSetlike();
|
||||
ok(m, "SimpleSet: got a TestInterfaceSetlike object");
|
||||
testExistence("SimpleSet: ", m, setlike_rw_properties);
|
||||
is(m.size, 0, "SimpleSet: size should be zero");
|
||||
ok(!m.has("test"), "SimpleSet: maplike has should return false");
|
||||
m1 = m.add("test");
|
||||
is(m, m1, "SimpleSet: return from set should be map object");
|
||||
is(m.size, 1, "SimpleSet: size should be 1");
|
||||
ok(m.has("test"), "SimpleSet: maplike has should return true");
|
||||
m2 = m.add("test2");
|
||||
is(m.size, 2, "SimpleSet: size should be 2");
|
||||
testSet = ["test", "test2"];
|
||||
testIndex = 0;
|
||||
m.forEach(function(v, k, o) {
|
||||
"use strict";
|
||||
is(o, m, "SimpleSet: foreach obj is correct");
|
||||
is(k, testSet[testIndex], "SimpleSet: foreach set key: " + k + " = " + testSet[testIndex]);
|
||||
testIndex += 1;
|
||||
});
|
||||
is(testIndex, 2, "SimpleSet: foreach ran correct number of times");
|
||||
ok(m.has("test2"), "SimpleSet: maplike has should return true");
|
||||
is(m.delete("test2"), true, "SimpleSet: maplike deletion should return true");
|
||||
is(m.size, 1, "SimpleSet: size should be 1");
|
||||
iterable = false;
|
||||
for (var e of m) {
|
||||
iterable = true;
|
||||
is(e, "test", "SimpleSet: iterable first array element should be key");
|
||||
}
|
||||
is(m[Symbol.iterator].length, 0, "SimpleSet: @@iterator symbol is correct length");
|
||||
is(m[Symbol.iterator].name, "[Symbol.iterator]", "SimpleSet: @@iterator symbol has correct name");
|
||||
ok(iterable, "SimpleSet: @@iterator symbol resolved correctly");
|
||||
for (var k of m.keys()) {
|
||||
is(k, "test", "SimpleSet: first keys element should be 'test'");
|
||||
}
|
||||
for (var v of m.values()) {
|
||||
is(v, "test", "SimpleSet: first values elements should be 'test'");
|
||||
}
|
||||
for (var e of m.entries()) {
|
||||
is(e[0], "test", "SimpleSet: Entries first array element should be 'test'");
|
||||
is(e[1], "test", "SimpleSet: Entries second array element should be 'test'");
|
||||
}
|
||||
m.clear();
|
||||
is(m.size, 0, "SimpleSet: size should be 0 after clear");
|
||||
|
||||
// Map convenience function test
|
||||
info("Testing map convenience functions");
|
||||
m = new TestInterfaceMaplike();
|
||||
ok(m, "MapConvenience: got a TestInterfaceMaplike object");
|
||||
is(m.size, 0, "MapConvenience: size should be zero");
|
||||
ok(!m.hasInternal("test"), "MapConvenience: maplike hasInternal should return false");
|
||||
m.setInternal("test", 1);
|
||||
is(m.size, 1, "MapConvenience: size should be 1");
|
||||
ok(m.hasInternal("test"), "MapConvenience: maplike hasInternal should return true");
|
||||
is(m.get("test"), 1, "MapConvenience: maplike get should return value entered");
|
||||
m2 = m.setInternal("test2", 2);
|
||||
is(m.size, 2, "size should be 2");
|
||||
ok(m.hasInternal("test2"), "MapConvenience: maplike hasInternal should return true");
|
||||
is(m.get("test2"), 2, "MapConvenience: maplike get should return value entered");
|
||||
is(m.deleteInternal("test2"), true, "MapConvenience: maplike deleteInternal should return true");
|
||||
is(m.size, 1, "MapConvenience: size should be 1");
|
||||
m.clearInternal();
|
||||
is(m.size, 0, "MapConvenience: size should be 0 after clearInternal");
|
||||
|
||||
// Map convenience function test using objects and readonly
|
||||
|
||||
info("Testing Map convenience function test using objects and readonly");
|
||||
m = new TestInterfaceMaplikeObject();
|
||||
ok(m, "ReadOnlyMapConvenience: got a TestInterfaceMaplikeObject object");
|
||||
is(m.size, 0, "ReadOnlyMapConvenience: size should be zero");
|
||||
is(m["set"], undefined, "ReadOnlyMapConvenience: readonly map, should be no set function");
|
||||
is(m["clear"], undefined, "ReadOnlyMapConvenience: readonly map, should be no clear function");
|
||||
is(m["delete"], undefined, "ReadOnlyMapConvenience: readonly map, should be no delete function");
|
||||
ok(!m.hasInternal("test"), "ReadOnlyMapConvenience: maplike hasInternal should return false");
|
||||
m.setInternal("test");
|
||||
is(m.size, 1, "size should be 1");
|
||||
ok(m.hasInternal("test"), "ReadOnlyMapConvenience: maplike hasInternal should return true");
|
||||
m2 = m.setInternal("test2");
|
||||
is(m.size, 2, "size should be 2");
|
||||
ok(m.hasInternal("test2"), "ReadOnlyMapConvenience: maplike hasInternal should return true");
|
||||
is(m.deleteInternal("test2"), true, "ReadOnlyMapConvenience: maplike deleteInternal should return true");
|
||||
is(m.size, 1, "ReadOnlyMapConvenience: size should be 1");
|
||||
m.clearInternal();
|
||||
is(m.size, 0, "ReadOnlyMapConvenience: size should be 0 after clearInternal");
|
||||
|
||||
// JS implemented map creation convenience function test
|
||||
|
||||
info("JSMapConvenience: Testing JS implemented map creation convenience functions");
|
||||
m = new TestInterfaceJSMaplike();
|
||||
ok(m, "JSMapConvenience: got a TestInterfaceJSMaplike object");
|
||||
is(m.size, 0, "JSMapConvenience: size should be zero");
|
||||
ok(!m.has("test"), "JSMapConvenience: maplike has should return false");
|
||||
m.setInternal("test", 1);
|
||||
is(m.size, 1, "JSMapConvenience: size should be 1");
|
||||
ok(m.has("test"), "JSMapConvenience: maplike has should return true");
|
||||
is(m.get("test"), 1, "JSMapConvenience: maplike get should return value entered");
|
||||
m2 = m.setInternal("test2", 2);
|
||||
is(m.size, 2, "JSMapConvenience: size should be 2");
|
||||
ok(m.has("test2"), "JSMapConvenience: maplike has should return true");
|
||||
is(m.get("test2"), 2, "JSMapConvenience: maplike get should return value entered");
|
||||
is(m.deleteInternal("test2"), true, "JSMapConvenience: maplike deleteInternal should return true");
|
||||
is(m.size, 1, "JSMapConvenience: size should be 1");
|
||||
for (var k of m.keys()) {
|
||||
is(k, "test", "JSMapConvenience: first keys element should be 'test'");
|
||||
}
|
||||
for (var v of m.values()) {
|
||||
is(v, 1, "JSMapConvenience: first values elements should be 1");
|
||||
}
|
||||
for (var e of m.entries()) {
|
||||
is(e[0], "test", "JSMapConvenience: entries first array element should be 'test'");
|
||||
is(e[1], 1, "JSMapConvenience: entries second array element should be 1");
|
||||
}
|
||||
m.clearInternal();
|
||||
is(m.size, 0, "JSMapConvenience: size should be 0 after clearInternal");
|
||||
|
||||
// Test this override for forEach
|
||||
info("ForEachThisOverride: Testing this override for forEach");
|
||||
m = new TestInterfaceMaplike();
|
||||
m.set("test", 1);
|
||||
m.forEach(function(v, k, o) {
|
||||
"use strict";
|
||||
is(o, m, "ForEachThisOverride: foreach obj is correct");
|
||||
is(this, 5, "ForEachThisOverride: 'this' value should be correct");
|
||||
}, 5);
|
||||
|
||||
// Test defaulting arguments on maplike to undefined
|
||||
info("MapArgsDefault: Testing maplike defaulting arguments to undefined");
|
||||
m = new TestInterfaceMaplike();
|
||||
m.set();
|
||||
is(m.size, 1, "MapArgsDefault: should have 1 entry");
|
||||
m.forEach(function(v, k) {
|
||||
"use strict";
|
||||
is(typeof k, "string", "MapArgsDefault: key is a string");
|
||||
is(k, "undefined", "MapArgsDefault: key is the string undefined");
|
||||
is(v, 0, "MapArgsDefault: value is 0");
|
||||
});
|
||||
is(m.get(), 0, "MapArgsDefault: no argument to get() returns correct value");
|
||||
m.delete();
|
||||
is(m.size, 0, "MapArgsDefault: should have 0 entries");
|
||||
|
||||
// Test defaulting arguments on setlike to undefined
|
||||
info("SetArgsDefault: Testing setlike defaulting arguments to undefined");
|
||||
m = new TestInterfaceSetlike();
|
||||
m.add();
|
||||
is(m.size, 1, "SetArgsDefault: should have 1 entry");
|
||||
m.forEach(function(v, k) {
|
||||
"use strict";
|
||||
is(typeof k, "string", "SetArgsDefault: key is a string");
|
||||
is(k, "undefined", "SetArgsDefault: key is the string undefined");
|
||||
});
|
||||
m.delete();
|
||||
is(m.size, 0, "SetArgsDefault: should have 0 entries");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
68
dom/bindings/test/test_bug1123516_maplikesetlikechrome.xul
Normal file
68
dom/bindings/test/test_bug1123516_maplikesetlikechrome.xul
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1123516
|
||||
-->
|
||||
<window title="Mozilla Bug 1123516"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<iframe id="t"></iframe>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1123516"
|
||||
target="_blank">Mozilla Bug 1123516</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/** Test for Bug 1123516 **/
|
||||
const Cu = Components.utils;
|
||||
function doTest() {
|
||||
var win = $("t").contentWindow;
|
||||
var sandbox = Components.utils.Sandbox(win, { sandboxPrototype: win });
|
||||
is(sandbox._content, undefined, "_content does nothing over Xray");
|
||||
// Test cross-compartment usage of maplike/setlike WebIDL structures.
|
||||
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, function() {
|
||||
try {
|
||||
var maplike = Components.utils.evalInSandbox("var m = new TestInterfaceMaplike(); m;", sandbox);
|
||||
maplike.set("test2", 2);
|
||||
is(maplike.get("test2"), 2, "Should be able to create and use maplike/setlike across compartments");
|
||||
var test = Components.utils.evalInSandbox("m.get('test2');", sandbox);
|
||||
is(test, 2, "Maplike/setlike should still work in original compartment");
|
||||
is(maplike.size, 1, "Testing size retrieval across compartments");
|
||||
} catch(e) {
|
||||
ok(false, "Shouldn't throw when working with cross-compartment maplike/setlike interfaces " + e)
|
||||
};
|
||||
try {
|
||||
var setlike = Components.utils.evalInSandbox("var m = new TestInterfaceSetlikeNode(); m.add(document.documentElement); m;", sandbox);
|
||||
is(TestInterfaceSetlikeNode.prototype.has.call(setlike, win.document.documentElement), true,
|
||||
"Cross-compartment unwrapping/comparison has works");
|
||||
// TODO: Should throw until iterators are handled by Xrays, Bug 1023984
|
||||
try {
|
||||
var e = TestInterfaceSetlikeNode.prototype.keys.call(setlike);
|
||||
ok(false, "Calling iterators via xrays should fail");
|
||||
} catch(e) {
|
||||
ok(true, "Calling iterators via xrays should fail");
|
||||
}
|
||||
|
||||
setlike.forEach((v,k,t) => { is(v, win.document.documentElement, "Cross-compartment forEach works"); });
|
||||
TestInterfaceSetlikeNode.prototype.forEach.call(setlike,
|
||||
(v,k,t) => { is(v, win.document.documentElement, "Cross-compartment forEach works"); });
|
||||
is(TestInterfaceSetlikeNode.prototype.delete.call(setlike, win.document.documentElement), true,
|
||||
"Cross-compartment unwrapping/comparison delete works");
|
||||
} catch(e) {
|
||||
ok(false, "Shouldn't throw when working with cross-compartment maplike/setlike interfaces " + e)
|
||||
};
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
@ -105,6 +105,11 @@ private:
|
||||
|
||||
void UpdateMustKeepAlive();
|
||||
|
||||
bool IsCertainlyAliveForCC() const override
|
||||
{
|
||||
return mIsKeptAlive;
|
||||
}
|
||||
|
||||
nsRefPtr<BroadcastChannelChild> mActor;
|
||||
nsTArray<nsRefPtr<BroadcastChannelMessage>> mPendingMessages;
|
||||
|
||||
|
@ -62,8 +62,7 @@ function testKeys(win) {
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({'set': [['browser.privatebrowing.autostart', true],
|
||||
['dom.caches.enabled', true],
|
||||
SpecialPowers.pushPrefEnv({'set': [['dom.caches.enabled', true],
|
||||
['dom.caches.testing.enabled', true]]},
|
||||
function() {
|
||||
var privateWin = OpenBrowserWindow({private: true});
|
||||
|
@ -1913,12 +1913,12 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile)
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
if (!aFile) {
|
||||
return JSVAL_NULL;
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
if (aFile->mEditable) {
|
||||
// TODO - needs janv's file handle support.
|
||||
return JSVAL_NULL;
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
nsString fullPath;
|
||||
@ -2531,7 +2531,7 @@ public:
|
||||
}
|
||||
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> result(cx, JSVAL_NULL);
|
||||
JS::Rooted<JS::Value> result(cx, JS::NullValue());
|
||||
|
||||
if (mFile) {
|
||||
result = nsIFileToJsval(window, mFile);
|
||||
|
@ -48,10 +48,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
|
||||
if (tmp->IsBlack()) {
|
||||
if (tmp->IsBlack() || tmp->IsCertainlyAliveForCC()) {
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->MarkForCC();
|
||||
}
|
||||
if (!tmp->IsBlack() && tmp->PreservingWrapper()) {
|
||||
// This marks the wrapper black.
|
||||
tmp->GetWrapper();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
|
@ -167,6 +167,14 @@ protected:
|
||||
|
||||
nsresult WantsUntrusted(bool* aRetVal);
|
||||
|
||||
// If this method returns true your object is kept alive until it returns
|
||||
// false. You can use this method instead using
|
||||
// NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN macro.
|
||||
virtual bool IsCertainlyAliveForCC() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<EventListenerManager> mListenerManager;
|
||||
// Make |event| trusted and dispatch |aEvent| to |this|.
|
||||
nsresult DispatchTrustedEvent(nsIDOMEvent* aEvent);
|
||||
|
@ -1543,12 +1543,12 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
|
||||
}
|
||||
|
||||
if (isValidUrlEncodedMimeType) {
|
||||
nsRefPtr<URLSearchParams> params = new URLSearchParams(nullptr);
|
||||
params->ParseInput(data);
|
||||
URLParams params;
|
||||
params.ParseInput(data);
|
||||
|
||||
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
|
||||
FillFormIterator iterator(fd);
|
||||
DebugOnly<bool> status = params->ForEach(iterator);
|
||||
DebugOnly<bool> status = params.ForEach(iterator);
|
||||
MOZ_ASSERT(status);
|
||||
|
||||
localPromise->MaybeResolve(fd);
|
||||
|
@ -503,7 +503,7 @@ TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName,
|
||||
const nsAString& aJSONData)
|
||||
{
|
||||
AutoSafeJSContext cx;
|
||||
JS::Rooted<JS::Value> json(cx, JSVAL_NULL);
|
||||
JS::Rooted<JS::Value> json(cx, JS::NullValue());
|
||||
StructuredCloneData cloneData;
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (JS_ParseJSON(cx,
|
||||
|
@ -100,12 +100,12 @@ IsTypeSupported(const nsAString& aType)
|
||||
|| AndroidBridge::Bridge()->GetAPIVersion() < 16
|
||||
#endif
|
||||
)) {
|
||||
break;
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
if ((mimeType.EqualsASCII("video/webm") ||
|
||||
mimeType.EqualsASCII("audio/webm")) &&
|
||||
!Preferences::GetBool("media.mediasource.webm.enabled", false)) {
|
||||
break;
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
|
@ -192,29 +192,6 @@ MessagePortBase::MessagePortBase()
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(MessagePort)
|
||||
bool isBlack = tmp->IsBlack();
|
||||
if (isBlack || tmp->mIsKeptAlive) {
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->MarkForCC();
|
||||
}
|
||||
if (!isBlack && tmp->PreservingWrapper()) {
|
||||
// This marks the wrapper black.
|
||||
tmp->GetWrapper();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(MessagePort)
|
||||
return tmp->
|
||||
IsBlackAndDoesNotNeedTracing(static_cast<DOMEventTargetHelper*>(tmp));
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(MessagePort)
|
||||
return tmp->IsBlack();
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
||||
MessagePortBase)
|
||||
if (tmp->mDispatchRunnable) {
|
||||
@ -235,10 +212,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MessagePort,
|
||||
MessagePortBase)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
|
@ -75,8 +75,8 @@ public:
|
||||
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(MessagePort,
|
||||
DOMEventTargetHelper)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
|
||||
MessagePortBase)
|
||||
|
||||
static already_AddRefed<MessagePort>
|
||||
Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
|
||||
@ -177,6 +177,11 @@ private:
|
||||
// We release the object when the port is closed or disentangled.
|
||||
void UpdateMustKeepAlive();
|
||||
|
||||
bool IsCertainlyAliveForCC() const override
|
||||
{
|
||||
return mIsKeptAlive;
|
||||
}
|
||||
|
||||
nsAutoPtr<workers::WorkerFeature> mWorkerFeature;
|
||||
|
||||
nsRefPtr<DispatchEventRunnable> mDispatchRunnable;
|
||||
|
@ -205,7 +205,7 @@ MobileMessageCallback::NotifyMessageDeleted(bool *aDeleted, uint32_t aSize)
|
||||
{
|
||||
if (aSize == 1) {
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> val(cx, aDeleted[0] ? JSVAL_TRUE : JSVAL_FALSE);
|
||||
JS::Rooted<JS::Value> val(cx, JS::BooleanValue(*aDeleted));
|
||||
return NotifySuccess(val);
|
||||
}
|
||||
|
||||
@ -234,7 +234,7 @@ NS_IMETHODIMP
|
||||
MobileMessageCallback::NotifyMessageMarkedRead(bool aRead)
|
||||
{
|
||||
AutoJSContext cx;
|
||||
JS::Rooted<JS::Value> val(cx, aRead ? JSVAL_TRUE : JSVAL_FALSE);
|
||||
JS::Rooted<JS::Value> val(cx, JS::BooleanValue(aRead));
|
||||
return NotifySuccess(val);
|
||||
}
|
||||
|
||||
|
@ -487,7 +487,7 @@ NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
|
||||
case NPVariantType_Void :
|
||||
return JS::UndefinedValue();
|
||||
case NPVariantType_Null :
|
||||
return JSVAL_NULL;
|
||||
return JS::NullValue();
|
||||
case NPVariantType_Bool :
|
||||
return BOOLEAN_TO_JSVAL(NPVARIANT_TO_BOOLEAN(*variant));
|
||||
case NPVariantType_Int32 :
|
||||
|
@ -915,7 +915,7 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
|
||||
#endif // defined(MOZ_WIDGET_GONK)
|
||||
|
||||
#if defined(DEBUG)
|
||||
JS::Rooted<JS::Value> valDebug(cx, JSVAL_TRUE);
|
||||
JS::Rooted<JS::Value> valDebug(cx, JS::TrueValue());
|
||||
if (!JS_SetProperty(cx, objSys, "DEBUG", valDebug)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7,7 +7,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267
|
||||
<window title="Mozilla Bug 741267"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
|
||||
</script>
|
||||
<iframe id="t"></iframe>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
|
47
dom/webidl/TestInterfaceJSMaplikeSetlike.webidl
Normal file
47
dom/webidl/TestInterfaceJSMaplikeSetlike.webidl
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
[Constructor(),
|
||||
Pref="dom.expose_test_interfaces"]
|
||||
interface TestInterfaceMaplike {
|
||||
maplike<DOMString, long>;
|
||||
void setInternal(DOMString aKey, long aValue);
|
||||
void clearInternal();
|
||||
boolean deleteInternal(DOMString aKey);
|
||||
boolean hasInternal(DOMString aKey);
|
||||
};
|
||||
|
||||
[Constructor(),
|
||||
Pref="dom.expose_test_interfaces"]
|
||||
interface TestInterfaceMaplikeObject {
|
||||
readonly maplike<DOMString, TestInterfaceMaplike>;
|
||||
void setInternal(DOMString aKey);
|
||||
void clearInternal();
|
||||
boolean deleteInternal(DOMString aKey);
|
||||
boolean hasInternal(DOMString aKey);
|
||||
};
|
||||
|
||||
[Pref="dom.expose_test_interfaces",
|
||||
JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1",
|
||||
Constructor()]
|
||||
interface TestInterfaceJSMaplike {
|
||||
readonly maplike<DOMString, long>;
|
||||
void setInternal(DOMString aKey, long aValue);
|
||||
void clearInternal();
|
||||
boolean deleteInternal(DOMString aKey);
|
||||
};
|
||||
|
||||
[Constructor(),
|
||||
Pref="dom.expose_test_interfaces"]
|
||||
interface TestInterfaceSetlike {
|
||||
setlike<DOMString>;
|
||||
};
|
||||
|
||||
[Constructor(),
|
||||
Pref="dom.expose_test_interfaces"]
|
||||
interface TestInterfaceSetlikeNode {
|
||||
setlike<Node>;
|
||||
};
|
@ -643,7 +643,9 @@ WEBIDL_FILES += [
|
||||
# We only expose our prefable test interfaces in debug builds, just to be on
|
||||
# the safe side.
|
||||
if CONFIG['MOZ_DEBUG']:
|
||||
WEBIDL_FILES += ['TestInterfaceJS.webidl', 'TestInterfaceJSDictionaries.webidl']
|
||||
WEBIDL_FILES += ['TestInterfaceJS.webidl',
|
||||
'TestInterfaceJSDictionaries.webidl',
|
||||
'TestInterfaceJSMaplikeSetlike.webidl']
|
||||
|
||||
if CONFIG['MOZ_B2G_BT']:
|
||||
if CONFIG['MOZ_B2G_BT_API_V1']:
|
||||
|
@ -259,11 +259,12 @@ public:
|
||||
|
||||
nsRefPtr<mozilla::dom::URL> url;
|
||||
if (mBaseProxy) {
|
||||
url = mozilla::dom::URL::Constructor(mURL, mBaseProxy->URI(), mRv);
|
||||
url = mozilla::dom::URL::Constructor(nullptr, mURL, mBaseProxy->URI(),
|
||||
mRv);
|
||||
} else if (!mBase.IsVoid()) {
|
||||
url = mozilla::dom::URL::Constructor(mURL, mBase, mRv);
|
||||
url = mozilla::dom::URL::Constructor(nullptr, mURL, mBase, mRv);
|
||||
} else {
|
||||
url = mozilla::dom::URL::Constructor(mURL, nullptr, mRv);
|
||||
url = mozilla::dom::URL::Constructor(nullptr, mURL, nullptr, mRv);
|
||||
}
|
||||
|
||||
if (mRv.Failed()) {
|
||||
@ -580,10 +581,10 @@ URL::~URL()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
|
||||
JSObject*
|
||||
URL::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return URLBinding_workers::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
return URLBinding_workers::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
@ -952,7 +953,7 @@ void
|
||||
URL::CreateSearchParamsIfNeeded()
|
||||
{
|
||||
if (!mSearchParams) {
|
||||
mSearchParams = new URLSearchParams(this);
|
||||
mSearchParams = new URLSearchParams(nullptr, this);
|
||||
UpdateURLSearchParams();
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -26,6 +27,7 @@ class URLProxy;
|
||||
class ConstructorRunnable;
|
||||
|
||||
class URL final : public mozilla::dom::URLSearchParamsObserver
|
||||
, public nsWrapperCache
|
||||
{
|
||||
typedef mozilla::dom::URLSearchParams URLSearchParams;
|
||||
|
||||
@ -44,8 +46,8 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector);
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// Methods for WebIDL
|
||||
|
||||
|
@ -1187,7 +1187,7 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
if (NS_SUCCEEDED(mResponseTextResult)) {
|
||||
mResponseResult = mResponseTextResult;
|
||||
if (mResponseText.IsVoid()) {
|
||||
mResponse = JSVAL_NULL;
|
||||
mResponse.setNull();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -251,7 +251,7 @@ public:
|
||||
NullResponseText()
|
||||
{
|
||||
mStateData.mResponseText.SetIsVoid(true);
|
||||
mStateData.mResponse = JSVAL_NULL;
|
||||
mStateData.mResponse.setNull();
|
||||
}
|
||||
|
||||
bool MozAnon() const
|
||||
|
@ -565,6 +565,10 @@ bool
|
||||
SharedMemoryBasic::ShareToProcess(base::ProcessId pid,
|
||||
Handle* aNewHandle)
|
||||
{
|
||||
if (pid == getpid()) {
|
||||
*aNewHandle = mPort;
|
||||
return mach_port_mod_refs(mach_task_self(), *aNewHandle, MACH_PORT_RIGHT_SEND, 1) == KERN_SUCCESS;
|
||||
}
|
||||
StaticMutexAutoLock smal(gMutex);
|
||||
|
||||
MemoryPorts* ports = GetMemoryPortsForPid(pid);
|
||||
|
@ -16,7 +16,7 @@ class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild
|
||||
typedef mozilla::ipc::ProcessChild ProcessChild;
|
||||
|
||||
public:
|
||||
IPDLUnitTestProcessChild(ProcessId aParentPid) :
|
||||
explicit IPDLUnitTestProcessChild(ProcessId aParentPid) :
|
||||
ProcessChild(aParentPid)
|
||||
{ }
|
||||
|
||||
|
@ -42,7 +42,7 @@ class TestBridgeMainSubParent :
|
||||
public PTestBridgeMainSubParent
|
||||
{
|
||||
public:
|
||||
TestBridgeMainSubParent(Transport* aTransport)
|
||||
explicit TestBridgeMainSubParent(Transport* aTransport)
|
||||
: mTransport(aTransport)
|
||||
{}
|
||||
virtual ~TestBridgeMainSubParent() {}
|
||||
@ -126,7 +126,7 @@ class TestBridgeMainSubChild :
|
||||
public PTestBridgeMainSubChild
|
||||
{
|
||||
public:
|
||||
TestBridgeMainSubChild(Transport* aTransport)
|
||||
explicit TestBridgeMainSubChild(Transport* aTransport)
|
||||
: mGotHi(false)
|
||||
, mTransport(aTransport)
|
||||
{}
|
||||
|
@ -20,7 +20,7 @@ class TestDataStructuresSub :
|
||||
public PTestDataStructuresSubChild
|
||||
{
|
||||
public:
|
||||
TestDataStructuresSub(uint32_t i) : mI(i)
|
||||
explicit TestDataStructuresSub(uint32_t i) : mI(i)
|
||||
{ }
|
||||
virtual ~TestDataStructuresSub()
|
||||
{ }
|
||||
|
@ -40,7 +40,7 @@ namespace _ipdltest2 {
|
||||
class TestOpensOpenedParent : public PTestOpensOpenedParent
|
||||
{
|
||||
public:
|
||||
TestOpensOpenedParent(Transport* aTransport)
|
||||
explicit TestOpensOpenedParent(Transport* aTransport)
|
||||
: mTransport(aTransport)
|
||||
{}
|
||||
virtual ~TestOpensOpenedParent() {}
|
||||
@ -83,7 +83,7 @@ namespace _ipdltest2 {
|
||||
class TestOpensOpenedChild : public PTestOpensOpenedChild
|
||||
{
|
||||
public:
|
||||
TestOpensOpenedChild(Transport* aTransport)
|
||||
explicit TestOpensOpenedChild(Transport* aTransport)
|
||||
: mGotHi(false)
|
||||
, mTransport(aTransport)
|
||||
{}
|
||||
|
@ -22,7 +22,7 @@ class TestShutdownSubsubParent :
|
||||
public PTestShutdownSubsubParent
|
||||
{
|
||||
public:
|
||||
TestShutdownSubsubParent(bool expectParentDeleted) :
|
||||
explicit TestShutdownSubsubParent(bool expectParentDeleted) :
|
||||
mExpectParentDeleted(expectParentDeleted)
|
||||
{
|
||||
}
|
||||
@ -44,7 +44,7 @@ class TestShutdownSubParent :
|
||||
public PTestShutdownSubParent
|
||||
{
|
||||
public:
|
||||
TestShutdownSubParent(bool expectCrash) :
|
||||
explicit TestShutdownSubParent(bool expectCrash) :
|
||||
mExpectCrash(expectCrash),
|
||||
mDeletedCount(0)
|
||||
{
|
||||
@ -131,7 +131,7 @@ class TestShutdownSubsubChild :
|
||||
public PTestShutdownSubsubChild
|
||||
{
|
||||
public:
|
||||
TestShutdownSubsubChild(bool expectParentDeleted) :
|
||||
explicit TestShutdownSubsubChild(bool expectParentDeleted) :
|
||||
mExpectParentDeleted(expectParentDeleted)
|
||||
{
|
||||
}
|
||||
@ -152,7 +152,7 @@ class TestShutdownSubChild :
|
||||
public PTestShutdownSubChild
|
||||
{
|
||||
public:
|
||||
TestShutdownSubChild(bool expectCrash) : mExpectCrash(expectCrash)
|
||||
explicit TestShutdownSubChild(bool expectCrash) : mExpectCrash(expectCrash)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -367,7 +367,7 @@ XPCShellEnvironment::ProcessFile(JSContext *cx,
|
||||
JSErrorReporter older;
|
||||
|
||||
ok = JS_ExecuteScript(cx, script, &result);
|
||||
if (ok && result != JSVAL_VOID) {
|
||||
if (ok && !result.isUndefined()) {
|
||||
/* Suppress error reports from JS::ToString(). */
|
||||
older = JS_SetErrorReporter(JS_GetRuntime(cx), nullptr);
|
||||
str = JS::ToString(cx, result);
|
||||
@ -584,7 +584,7 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
|
||||
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
bool ok = JS_ExecuteScript(cx, script, &result);
|
||||
if (ok && result != JSVAL_VOID) {
|
||||
if (ok && !result.isUndefined()) {
|
||||
JSErrorReporter old = JS_SetErrorReporter(JS_GetRuntime(cx), nullptr);
|
||||
JSString* str = JS::ToString(cx, result);
|
||||
nsAutoJSString autoStr;
|
||||
|
@ -270,7 +270,7 @@ JavaScriptShared::toVariant(JSContext* cx, JS::HandleValue from, JSVariant* to)
|
||||
{
|
||||
RootedObject obj(cx, from.toObjectOrNull());
|
||||
if (!obj) {
|
||||
MOZ_ASSERT(from == JSVAL_NULL);
|
||||
MOZ_ASSERT(from.isNull());
|
||||
*to = NullVariant();
|
||||
return true;
|
||||
}
|
||||
|
@ -1676,6 +1676,7 @@ class ValueOperations
|
||||
bool isFalse() const { return value()->isFalse(); }
|
||||
bool isNumber() const { return value()->isNumber(); }
|
||||
bool isInt32() const { return value()->isInt32(); }
|
||||
bool isInt32(int32_t i32) const { return value()->isInt32(i32); }
|
||||
bool isDouble() const { return value()->isDouble(); }
|
||||
bool isString() const { return value()->isString(); }
|
||||
bool isSymbol() const { return value()->isSymbol(); }
|
||||
@ -1998,17 +1999,6 @@ PRIVATE_TO_JSVAL(void* ptr)
|
||||
return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr));
|
||||
}
|
||||
|
||||
// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
|
||||
// constructing values from scratch (e.g. Int32Value(0)). These constants are
|
||||
// stored in memory and initialized at startup, so testing against them and
|
||||
// using them requires memory loads and will be correspondingly slow.
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
|
||||
|
||||
namespace JS {
|
||||
|
||||
extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue;
|
||||
|
@ -131,6 +131,11 @@ static const unsigned PushedRetAddr = 4;
|
||||
static const unsigned PushedFP = 16;
|
||||
static const unsigned StoredFP = 20;
|
||||
static const unsigned PostStorePrePopFP = 4;
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
static const unsigned PushedRetAddr = 0;
|
||||
static const unsigned PushedFP = 0;
|
||||
static const unsigned StoredFP = 0;
|
||||
static const unsigned PostStorePrePopFP = 0;
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
static const unsigned PushedRetAddr = 8;
|
||||
static const unsigned PushedFP = 24;
|
||||
@ -216,7 +221,7 @@ GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, AsmJSExit:
|
||||
Label* profilingReturn)
|
||||
{
|
||||
Register scratch = ABIArgGenerator::NonReturn_VolatileReg0;
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS)
|
||||
Register scratch2 = ABIArgGenerator::NonReturn_VolatileReg1;
|
||||
#endif
|
||||
|
||||
@ -240,11 +245,11 @@ GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, AsmJSExit:
|
||||
// and the async interrupt exit. Since activation.fp can be read at any
|
||||
// time and still points to the current frame, be careful to only update
|
||||
// sp after activation.fp has been repointed to the caller's frame.
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS)
|
||||
masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
|
||||
masm.storePtr(scratch2, Address(scratch, AsmJSActivation::offsetOfFP()));
|
||||
DebugOnly<uint32_t> prePop = masm.currentOffset();
|
||||
masm.add32(Imm32(4), masm.getStackPointer());
|
||||
masm.addToStackPtr(Imm32(sizeof(void *)));
|
||||
MOZ_ASSERT(PostStorePrePopFP == masm.currentOffset() - prePop);
|
||||
#else
|
||||
masm.pop(Address(scratch, AsmJSActivation::offsetOfFP()));
|
||||
|
@ -1787,6 +1787,9 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
||||
BOffImm calleeOffset;
|
||||
callerInsn->as<InstBLImm>()->extractImm(&calleeOffset);
|
||||
void* callee = calleeOffset.getDest(callerInsn);
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH();
|
||||
void* callee = nullptr;
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
|
||||
void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
|
||||
@ -1811,6 +1814,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
||||
X86Encoding::SetRel32(callerRetAddr, newCallee);
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always);
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH();
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
Assembler::WriteLuiOriInstructions(instr, instr->next(),
|
||||
ScratchRegister, (uint32_t)newCallee);
|
||||
@ -1874,6 +1879,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
||||
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
|
||||
new (jump) InstNOP();
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH();
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
Instruction* instr = (Instruction*)jump;
|
||||
if (enabled) {
|
||||
|
@ -1164,8 +1164,8 @@ RedirectJitCodeToInterruptCheck(JSRuntime* rt, CONTEXT* context)
|
||||
const AsmJSModule& module = activation->module();
|
||||
|
||||
#ifdef JS_SIMULATOR
|
||||
if (module.containsFunctionPC((void*)rt->simulator()->get_pc()))
|
||||
rt->simulator()->set_resume_pc(int32_t(module.interruptExit()));
|
||||
if (module.containsFunctionPC(rt->simulator()->get_pc_as<void*>()))
|
||||
rt->simulator()->set_resume_pc(module.interruptExit());
|
||||
#endif
|
||||
|
||||
uint8_t** ppc = ContextToPC(context);
|
||||
|
@ -9112,7 +9112,8 @@ GenerateAsyncInterruptExit(ModuleCompiler& m, Label* throwLabel)
|
||||
masm.transferReg(lr);
|
||||
masm.finishDataTransfer();
|
||||
masm.ret();
|
||||
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH();
|
||||
#elif defined (JS_CODEGEN_NONE)
|
||||
MOZ_CRASH();
|
||||
#else
|
||||
|
@ -437,44 +437,138 @@ function CanonicalizeLanguageTag(locale) {
|
||||
}
|
||||
|
||||
|
||||
// mappings from some commonly used old-style language tags to current flavors
|
||||
// with script codes
|
||||
function localeContainsNoUnicodeExtensions(locale) {
|
||||
// No "-u-", no possible Unicode extension.
|
||||
if (callFunction(std_String_indexOf, locale, "-u-") === -1)
|
||||
return true;
|
||||
|
||||
// "-u-" within privateuse also isn't one.
|
||||
if (callFunction(std_String_indexOf, locale, "-u-") > callFunction(std_String_indexOf, locale, "-x-"))
|
||||
return true;
|
||||
|
||||
// An entirely-privateuse tag doesn't contain extensions.
|
||||
if (callFunction(std_String_startsWith, locale, "x-"))
|
||||
return true;
|
||||
|
||||
// Otherwise, we have a Unicode extension sequence.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// The last-ditch locale is used if none of the available locales satisfies a
|
||||
// request. "en-GB" is used based on the assumptions that English is the most
|
||||
// common second language, that both en-GB and en-US are normally available in
|
||||
// an implementation, and that en-GB is more representative of the English used
|
||||
// in other locales.
|
||||
function lastDitchLocale() {
|
||||
// Per bug 1177929, strings don't clone out of self-hosted code as atoms,
|
||||
// breaking IonBuilder::constant. Put this in a function for now.
|
||||
return "en-GB";
|
||||
}
|
||||
|
||||
|
||||
// Certain old, commonly-used language tags that lack a script, are expected to
|
||||
// nonetheless imply one. This object maps these old-style tags to modern
|
||||
// equivalents.
|
||||
var oldStyleLanguageTagMappings = {
|
||||
"pa-PK": "pa-Arab-PK",
|
||||
"zh-CN": "zh-Hans-CN",
|
||||
"zh-HK": "zh-Hant-HK",
|
||||
"zh-SG": "zh-Hans-SG",
|
||||
"zh-TW": "zh-Hant-TW"
|
||||
"zh-TW": "zh-Hant-TW",
|
||||
};
|
||||
|
||||
|
||||
var localeCandidateCache = {
|
||||
runtimeDefaultLocale: undefined,
|
||||
candidateDefaultLocale: undefined,
|
||||
};
|
||||
|
||||
|
||||
var localeCache = {
|
||||
runtimeDefaultLocale: undefined,
|
||||
defaultLocale: undefined,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compute the candidate default locale: the locale *requested* to be used as
|
||||
* the default locale. We'll use it if and only if ICU provides support (maybe
|
||||
* fallback support, e.g. supporting "de-ZA" through "de" support implied by a
|
||||
* "de-DE" locale).
|
||||
*/
|
||||
function DefaultLocaleIgnoringAvailableLocales() {
|
||||
const runtimeDefaultLocale = RuntimeDefaultLocale();
|
||||
if (runtimeDefaultLocale === localeCandidateCache.runtimeDefaultLocale)
|
||||
return localeCandidateCache.candidateDefaultLocale;
|
||||
|
||||
// If we didn't get a cache hit, compute the candidate default locale and
|
||||
// cache it. Fall back on the last-ditch locale when necessary.
|
||||
var candidate;
|
||||
if (!IsStructurallyValidLanguageTag(runtimeDefaultLocale)) {
|
||||
candidate = lastDitchLocale();
|
||||
} else {
|
||||
candidate = CanonicalizeLanguageTag(runtimeDefaultLocale);
|
||||
|
||||
// The default locale must be in [[availableLocales]], and that list
|
||||
// must not contain any locales with Unicode extension sequences, so
|
||||
// remove any present in the candidate.
|
||||
candidate = removeUnicodeExtensions(candidate);
|
||||
|
||||
if (callFunction(std_Object_hasOwnProperty, oldStyleLanguageTagMappings, candidate))
|
||||
candidate = oldStyleLanguageTagMappings[candidate];
|
||||
}
|
||||
|
||||
// Cache the candidate locale until the runtime default locale changes.
|
||||
localeCandidateCache.runtimeDefaultLocale = runtimeDefaultLocale;
|
||||
localeCandidateCache.candidateDefaultLocale = candidate;
|
||||
|
||||
assert(IsStructurallyValidLanguageTag(candidate),
|
||||
"the candidate must be structurally valid");
|
||||
assert(localeContainsNoUnicodeExtensions(candidate),
|
||||
"the candidate must not contain a Unicode extension sequence");
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the BCP 47 language tag for the host environment's current locale.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, 6.2.4.
|
||||
*/
|
||||
function DefaultLocale() {
|
||||
// The locale of last resort is used if none of the available locales
|
||||
// satisfies a request. "en-GB" is used based on the assumptions that
|
||||
// English is the most common second language, that both en-GB and en-US
|
||||
// are normally available in an implementation, and that en-GB is more
|
||||
// representative of the English used in other locales.
|
||||
var localeOfLastResort = "en-GB";
|
||||
const runtimeDefaultLocale = RuntimeDefaultLocale();
|
||||
if (runtimeDefaultLocale === localeCache.runtimeDefaultLocale)
|
||||
return localeCache.defaultLocale;
|
||||
|
||||
var locale = RuntimeDefaultLocale();
|
||||
if (!IsStructurallyValidLanguageTag(locale))
|
||||
return localeOfLastResort;
|
||||
|
||||
locale = CanonicalizeLanguageTag(locale);
|
||||
if (callFunction(std_Object_hasOwnProperty, oldStyleLanguageTagMappings, locale))
|
||||
locale = oldStyleLanguageTagMappings[locale];
|
||||
|
||||
if (!(collatorInternalProperties.availableLocales()[locale] &&
|
||||
numberFormatInternalProperties.availableLocales()[locale] &&
|
||||
dateTimeFormatInternalProperties.availableLocales()[locale]))
|
||||
// If we didn't have a cache hit, compute the candidate default locale.
|
||||
// Then use it as the actual default locale if ICU supports that locale
|
||||
// (perhaps via fallback). Otherwise use the last-ditch locale.
|
||||
var candidate = DefaultLocaleIgnoringAvailableLocales();
|
||||
var locale;
|
||||
if (BestAvailableLocaleIgnoringDefault(collatorInternalProperties.availableLocales(),
|
||||
candidate) &&
|
||||
BestAvailableLocaleIgnoringDefault(numberFormatInternalProperties.availableLocales(),
|
||||
candidate) &&
|
||||
BestAvailableLocaleIgnoringDefault(dateTimeFormatInternalProperties.availableLocales(),
|
||||
candidate))
|
||||
{
|
||||
locale = localeOfLastResort;
|
||||
locale = candidate;
|
||||
} else {
|
||||
locale = lastDitchLocale();
|
||||
}
|
||||
|
||||
assert(IsStructurallyValidLanguageTag(locale),
|
||||
"the computed default locale must be structurally valid");
|
||||
assert(locale === CanonicalizeLanguageTag(locale),
|
||||
"the computed default locale must be canonical");
|
||||
assert(localeContainsNoUnicodeExtensions(locale),
|
||||
"the computed default locale must not contain a Unicode extension sequence");
|
||||
|
||||
localeCache.runtimeDefaultLocale = runtimeDefaultLocale;
|
||||
localeCache.defaultLocale = locale;
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
@ -500,22 +594,28 @@ function IsWellFormedCurrencyCode(currency) {
|
||||
|
||||
/********** Locale and Parameter Negotiation **********/
|
||||
|
||||
|
||||
/**
|
||||
* Add old-style language tags without script code for locales that in current
|
||||
* usage would include a script subtag. Returns the availableLocales argument
|
||||
* provided.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, 9.1.
|
||||
* usage would include a script subtag. Also add an entry for the last-ditch
|
||||
* locale, in case ICU doesn't directly support it (but does support it through
|
||||
* fallback, e.g. supporting "en-GB" indirectly using "en" support).
|
||||
*/
|
||||
function addOldStyleLanguageTags(availableLocales) {
|
||||
function addSpecialMissingLanguageTags(availableLocales) {
|
||||
// Certain old-style language tags lack a script code, but in current usage
|
||||
// they *would* include a script code. Map these over to modern forms.
|
||||
var oldStyleLocales = std_Object_getOwnPropertyNames(oldStyleLanguageTagMappings);
|
||||
for (var i = 0; i < oldStyleLocales.length; i++) {
|
||||
var oldStyleLocale = oldStyleLocales[i];
|
||||
if (availableLocales[oldStyleLanguageTagMappings[oldStyleLocale]])
|
||||
availableLocales[oldStyleLocale] = true;
|
||||
}
|
||||
return availableLocales;
|
||||
|
||||
// Also forcibly provide the last-ditch locale.
|
||||
var lastDitch = lastDitchLocale();
|
||||
assert(lastDitch === "en-GB" && availableLocales["en"],
|
||||
"shouldn't be a need to add every locale implied by the last-" +
|
||||
"ditch locale, merely just the last-ditch locale");
|
||||
availableLocales[lastDitch] = true;
|
||||
}
|
||||
|
||||
|
||||
@ -553,6 +653,50 @@ function CanonicalizeLocaleList(locales) {
|
||||
}
|
||||
|
||||
|
||||
function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLocale) {
|
||||
assert(IsStructurallyValidLanguageTag(locale), "invalid BestAvailableLocale locale structure");
|
||||
assert(locale === CanonicalizeLanguageTag(locale), "non-canonical BestAvailableLocale locale");
|
||||
assert(localeContainsNoUnicodeExtensions(locale), "locale must contain no Unicode extensions");
|
||||
|
||||
// In the spec, [[availableLocales]] is formally a list of all available
|
||||
// locales. But in our implementation, it's an *incomplete* list, not
|
||||
// necessarily including the default locale (and all locales implied by it,
|
||||
// e.g. "de" implied by "de-CH"), if that locale isn't in every
|
||||
// [[availableLocales]] list (because that locale is supported through
|
||||
// fallback, e.g. "de-CH" supported through "de").
|
||||
//
|
||||
// If we're considering the default locale, augment the spec loop with
|
||||
// additional checks to also test whether the current prefix is a prefix of
|
||||
// the default locale.
|
||||
|
||||
var defaultLocale;
|
||||
if (considerDefaultLocale)
|
||||
defaultLocale = DefaultLocale();
|
||||
|
||||
var candidate = locale;
|
||||
while (true) {
|
||||
if (availableLocales[candidate])
|
||||
return candidate;
|
||||
|
||||
if (considerDefaultLocale && candidate.length <= defaultLocale.length) {
|
||||
if (candidate === defaultLocale)
|
||||
return candidate;
|
||||
if (callFunction(std_String_startsWith, defaultLocale, candidate + "-"))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
var pos = callFunction(std_String_lastIndexOf, candidate, "-");
|
||||
if (pos === -1)
|
||||
return undefined;
|
||||
|
||||
if (pos >= 2 && candidate[pos - 2] === "-")
|
||||
pos -= 2;
|
||||
|
||||
candidate = callFunction(std_String_substring, candidate, 0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares a BCP 47 language tag against the locales in availableLocales
|
||||
* and returns the best available match. Uses the fallback
|
||||
@ -562,21 +706,16 @@ function CanonicalizeLocaleList(locales) {
|
||||
* Spec: RFC 4647, section 3.4.
|
||||
*/
|
||||
function BestAvailableLocale(availableLocales, locale) {
|
||||
assert(IsStructurallyValidLanguageTag(locale), "invalid BestAvailableLocale locale structure");
|
||||
assert(locale === CanonicalizeLanguageTag(locale), "non-canonical BestAvailableLocale locale");
|
||||
assert(callFunction(std_String_indexOf, locale, "-u-") === -1, "locale shouldn't contain -u-");
|
||||
return BestAvailableLocaleHelper(availableLocales, locale, true);
|
||||
}
|
||||
|
||||
var candidate = locale;
|
||||
while (true) {
|
||||
if (availableLocales[candidate])
|
||||
return candidate;
|
||||
var pos = callFunction(std_String_lastIndexOf, candidate, "-");
|
||||
if (pos === -1)
|
||||
return undefined;
|
||||
if (pos >= 2 && candidate[pos - 2] === "-")
|
||||
pos -= 2;
|
||||
candidate = callFunction(std_String_substring, candidate, 0, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identical to BestAvailableLocale, but does not consider the default locale
|
||||
* during computation.
|
||||
*/
|
||||
function BestAvailableLocaleIgnoringDefault(availableLocales, locale) {
|
||||
return BestAvailableLocaleHelper(availableLocales, locale, false);
|
||||
}
|
||||
|
||||
|
||||
@ -1357,8 +1496,10 @@ var collatorInternalProperties = {
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
return (this._availableLocales =
|
||||
addOldStyleLanguageTags(intl_Collator_availableLocales()));
|
||||
|
||||
locales = intl_Collator_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: ["co", "kn"]
|
||||
};
|
||||
@ -1471,8 +1612,10 @@ var numberFormatInternalProperties = {
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
return (this._availableLocales =
|
||||
addOldStyleLanguageTags(intl_NumberFormat_availableLocales()));
|
||||
|
||||
locales = intl_NumberFormat_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: ["nu"]
|
||||
};
|
||||
@ -2504,8 +2647,10 @@ var dateTimeFormatInternalProperties = {
|
||||
var locales = this._availableLocales;
|
||||
if (locales)
|
||||
return locales;
|
||||
return (this._availableLocales =
|
||||
addOldStyleLanguageTags(intl_DateTimeFormat_availableLocales()));
|
||||
|
||||
locales = intl_DateTimeFormat_availableLocales();
|
||||
addSpecialMissingLanguageTags(locales);
|
||||
return (this._availableLocales = locales);
|
||||
},
|
||||
relevantExtensionKeys: ["ca", "nu"]
|
||||
};
|
||||
|
@ -1354,7 +1354,6 @@ MapObject::extract(CallReceiver call)
|
||||
uint32_t
|
||||
MapObject::size(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
MOZ_ASSERT(MapObject::is(obj));
|
||||
ValueMap& map = extract(obj);
|
||||
static_assert(sizeof(map.count()) <= sizeof(uint32_t),
|
||||
"map count must be precisely representable as a JS number");
|
||||
@ -1380,8 +1379,6 @@ bool
|
||||
MapObject::get(JSContext* cx, HandleObject obj,
|
||||
HandleValue key, MutableHandleValue rval)
|
||||
{
|
||||
MOZ_ASSERT(MapObject::is(obj));
|
||||
|
||||
ValueMap& map = extract(obj);
|
||||
AutoHashableValueRooter k(cx);
|
||||
|
||||
@ -1413,8 +1410,6 @@ MapObject::get(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool
|
||||
MapObject::has(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
MOZ_ASSERT(MapObject::is(obj));
|
||||
|
||||
ValueMap& map = extract(obj);
|
||||
AutoHashableValueRooter k(cx);
|
||||
|
||||
@ -1469,7 +1464,23 @@ MapObject::set(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::delete_impl(JSContext* cx, CallArgs args)
|
||||
MapObject::delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
ValueMap &map = extract(obj);
|
||||
AutoHashableValueRooter k(cx);
|
||||
|
||||
if (!k.setValue(cx, key))
|
||||
return false;
|
||||
|
||||
if (!map.remove(k, rval)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::delete_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
// MapObject::mark does not mark deleted entries. Incremental GC therefore
|
||||
// requires that no RelocatableValue objects pointing to heap values be
|
||||
@ -1504,7 +1515,6 @@ bool
|
||||
MapObject::iterator(JSContext* cx, IteratorKind kind,
|
||||
HandleObject obj, MutableHandleValue iter)
|
||||
{
|
||||
MOZ_ASSERT(MapObject::is(obj));
|
||||
ValueMap& map = extract(obj);
|
||||
Rooted<JSObject*> iterobj(cx, MapIteratorObject::create(cx, obj, &map, kind));
|
||||
return iterobj && (iter.setObject(*iterobj), true);
|
||||
@ -1574,7 +1584,6 @@ MapObject::clear(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool
|
||||
MapObject::clear(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
MOZ_ASSERT(MapObject::is(obj));
|
||||
ValueMap& map = extract(obj);
|
||||
if (!map.clear()) {
|
||||
ReportOutOfMemory(cx);
|
||||
@ -1961,7 +1970,20 @@ SetObject::is(HandleValue v)
|
||||
return v.isObject() && v.toObject().hasClass(&class_) && v.toObject().as<SetObject>().getPrivate();
|
||||
}
|
||||
|
||||
ValueSet&
|
||||
bool
|
||||
SetObject::is(HandleObject o)
|
||||
{
|
||||
return o->hasClass(&class_) && o->as<SetObject>().getPrivate();
|
||||
}
|
||||
|
||||
ValueSet &
|
||||
SetObject::extract(HandleObject o)
|
||||
{
|
||||
MOZ_ASSERT(o->hasClass(&SetObject::class_));
|
||||
return *o->as<SetObject>().getData();
|
||||
}
|
||||
|
||||
ValueSet &
|
||||
SetObject::extract(CallReceiver call)
|
||||
{
|
||||
MOZ_ASSERT(call.thisv().isObject());
|
||||
@ -1969,6 +1991,16 @@ SetObject::extract(CallReceiver call)
|
||||
return *static_cast<SetObject&>(call.thisv().toObject()).getData();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SetObject::size(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
MOZ_ASSERT(SetObject::is(obj));
|
||||
ValueSet &set = extract(obj);
|
||||
static_assert(sizeof(set.count()) <= sizeof(uint32_t),
|
||||
"set count must be precisely representable as a JS number");
|
||||
return set.count();
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::size_impl(JSContext* cx, CallArgs args)
|
||||
{
|
||||
@ -2000,7 +2032,22 @@ SetObject::has_impl(JSContext* cx, CallArgs args)
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::has(JSContext* cx, unsigned argc, Value* vp)
|
||||
SetObject::has(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
MOZ_ASSERT(SetObject::is(obj));
|
||||
|
||||
ValueSet &set = extract(obj);
|
||||
AutoHashableValueRooter k(cx);
|
||||
|
||||
if (!k.setValue(cx, key))
|
||||
return false;
|
||||
|
||||
*rval = set.has(k);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::has(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<SetObject::is, SetObject::has_impl>(cx, args);
|
||||
@ -2030,7 +2077,25 @@ SetObject::add(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::delete_impl(JSContext* cx, CallArgs args)
|
||||
SetObject::delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
MOZ_ASSERT(SetObject::is(obj));
|
||||
|
||||
ValueSet &set = extract(obj);
|
||||
AutoHashableValueRooter k(cx);
|
||||
|
||||
if (!k.setValue(cx, key))
|
||||
return false;
|
||||
|
||||
if (!set.remove(k, rval)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::delete_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(is(args.thisv()));
|
||||
|
||||
@ -2053,7 +2118,17 @@ SetObject::delete_(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::iterator_impl(JSContext* cx, CallArgs args, IteratorKind kind)
|
||||
SetObject::iterator(JSContext *cx, IteratorKind kind,
|
||||
HandleObject obj, MutableHandleValue iter)
|
||||
{
|
||||
MOZ_ASSERT(SetObject::is(obj));
|
||||
ValueSet &set = extract(obj);
|
||||
Rooted<JSObject*> iterobj(cx, SetIteratorObject::create(cx, obj, &set, kind));
|
||||
return iterobj && (iter.setObject(*iterobj), true);
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind)
|
||||
{
|
||||
Rooted<SetObject*> setobj(cx, &args.thisv().toObject().as<SetObject>());
|
||||
ValueSet& set = *setobj->getData();
|
||||
@ -2091,7 +2166,19 @@ SetObject::entries(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::clear_impl(JSContext* cx, CallArgs args)
|
||||
SetObject::clear(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
MOZ_ASSERT(SetObject::is(obj));
|
||||
ValueSet &set = extract(obj);
|
||||
if (!set.clear()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetObject::clear_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
Rooted<SetObject*> setobj(cx, &args.thisv().toObject().as<SetObject>());
|
||||
if (!setobj->getData()->clear()) {
|
||||
@ -2127,6 +2214,98 @@ js::InitSelfHostingCollectionIteratorFunctions(JSContext* cx, HandleObject obj)
|
||||
return JS_DefineFunctions(cx, obj, selfhosting_collection_iterator_methods);
|
||||
}
|
||||
|
||||
/*** JS static utility functions *********************************************/
|
||||
|
||||
static
|
||||
bool
|
||||
forEach(const char* funcName, JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisArg)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
RootedId forEachId(cx, NameToId(cx->names().forEach));
|
||||
RootedFunction forEachFunc(cx, JS::GetSelfHostedFunction(cx, funcName, forEachId, 2));
|
||||
if (!forEachFunc)
|
||||
return false;
|
||||
InvokeArgs args(cx);
|
||||
if (!args.init(2))
|
||||
return false;
|
||||
args.setCallee(JS::ObjectValue(*forEachFunc));
|
||||
args.setThis(JS::ObjectValue(*obj));
|
||||
args[0].set(callbackFn);
|
||||
args[1].set(thisArg);
|
||||
return Invoke(cx, args);
|
||||
}
|
||||
|
||||
// Handles Clear/Size for public jsapi map/set access
|
||||
template<typename RetT>
|
||||
RetT
|
||||
CallObjFunc(RetT(*ObjFunc)(JSContext*, HandleObject), JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
// Always unwrap, in case this is an xray or cross-compartment wrapper.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
|
||||
// Enter the compartment of the backing object before calling functions on
|
||||
// it.
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
return ObjFunc(cx, unwrappedObj);
|
||||
}
|
||||
|
||||
// Handles Has/Delete for public jsapi map/set access
|
||||
bool
|
||||
CallObjFunc(bool(*ObjFunc)(JSContext *cx, HandleObject obj, HandleValue key, bool *rval),
|
||||
JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, key);
|
||||
|
||||
// Always unwrap, in case this is an xray or cross-compartment wrapper.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
|
||||
// If we're working with a wrapped map/set, rewrap the key into the
|
||||
// compartment of the unwrapped map/set.
|
||||
RootedValue wrappedKey(cx, key);
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey))
|
||||
return false;
|
||||
}
|
||||
return ObjFunc(cx, unwrappedObj, wrappedKey, rval);
|
||||
}
|
||||
|
||||
// Handles iterator generation for public jsapi map/set access
|
||||
template<typename Iter>
|
||||
bool
|
||||
CallObjFunc(bool(*ObjFunc)(JSContext* cx, Iter kind,
|
||||
HandleObject obj, MutableHandleValue iter),
|
||||
JSContext *cx, Iter iterType, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
// Always unwrap, in case this is an xray or cross-compartment wrapper.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
// Retrieve the iterator while in the unwrapped map/set's compartment,
|
||||
// otherwise we'll crash on a compartment assert.
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
if (!ObjFunc(cx, iterType, unwrappedObj, rval))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the caller is in a different compartment than the map/set, rewrap the
|
||||
// iterator object into the caller's compartment.
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, rval))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** JS public APIs **********************************************************/
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
@ -2138,63 +2317,182 @@ JS::NewMapObject(JSContext* cx)
|
||||
JS_PUBLIC_API(uint32_t)
|
||||
JS::MapSize(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return MapObject::size(cx, obj);
|
||||
return CallObjFunc<uint32_t>(&MapObject::size, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapGet(JSContext* cx, HandleObject obj,
|
||||
HandleValue key, MutableHandleValue rval)
|
||||
JS::MapGet(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key, rval);
|
||||
return MapObject::get(cx, obj, key, rval);
|
||||
assertSameCompartment(cx, obj, key, rval);
|
||||
|
||||
// Unwrap the object, and enter its compartment. If object isn't wrapped,
|
||||
// this is essentially a noop.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
RootedValue wrappedKey(cx, key);
|
||||
|
||||
// If we passed in a wrapper, wrap our key into its compartment now.
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey))
|
||||
return false;
|
||||
}
|
||||
if (!MapObject::get(cx, unwrappedObj, wrappedKey, rval))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we passed in a wrapper, wrap our return value on the way out.
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, rval))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapSet(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, key, val);
|
||||
|
||||
// Unwrap the object, and enter its compartment. If object isn't wrapped,
|
||||
// this is essentially a noop.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
|
||||
// If we passed in a wrapper, wrap both key and value before adding to
|
||||
// the map
|
||||
RootedValue wrappedKey(cx, key);
|
||||
RootedValue wrappedValue(cx, val);
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey) ||
|
||||
!JS_WrapValue(cx, &wrappedValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return MapObject::set(cx, unwrappedObj, wrappedKey, wrappedValue);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key);
|
||||
return MapObject::has(cx, obj, key, rval);
|
||||
return CallObjFunc(MapObject::has, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapSet(JSContext* cx, HandleObject obj,
|
||||
HandleValue key, HandleValue val)
|
||||
JS::MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, key, val);
|
||||
return MapObject::set(cx, obj, key, val);
|
||||
return CallObjFunc(MapObject::delete_, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapClear(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return MapObject::clear(cx, obj);
|
||||
return CallObjFunc(&MapObject::clear, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return MapObject::iterator(cx, MapObject::Keys, obj, rval);
|
||||
return CallObjFunc(&MapObject::iterator, cx, MapObject::Keys, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return MapObject::iterator(cx, MapObject::Values, obj, rval);
|
||||
return CallObjFunc(&MapObject::iterator, cx, MapObject::Values, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, rval);
|
||||
return MapObject::iterator(cx, MapObject::Entries, obj, rval);
|
||||
return CallObjFunc(&MapObject::iterator, cx, MapObject::Entries, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::MapForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
|
||||
{
|
||||
return forEach("MapForEach", cx, obj, callbackFn, thisVal);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS::NewSetObject(JSContext *cx)
|
||||
{
|
||||
return SetObject::create(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(uint32_t)
|
||||
JS::SetSize(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
return CallObjFunc<uint32_t>(&SetObject::size, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetAdd(JSContext *cx, HandleObject obj, HandleValue key)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, key);
|
||||
|
||||
// Unwrap the object, and enter its compartment. If object isn't wrapped,
|
||||
// this is essentially a noop.
|
||||
RootedObject unwrappedObj(cx);
|
||||
unwrappedObj = UncheckedUnwrap(obj);
|
||||
{
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
|
||||
// If we passed in a wrapper, wrap key before adding to the set
|
||||
RootedValue wrappedKey(cx, key);
|
||||
if (obj != unwrappedObj) {
|
||||
if (!JS_WrapValue(cx, &wrappedKey))
|
||||
return false;
|
||||
}
|
||||
return SetObject::add(cx, unwrappedObj, wrappedKey);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval)
|
||||
{
|
||||
return CallObjFunc(SetObject::has, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
|
||||
{
|
||||
return CallObjFunc(SetObject::delete_, cx, obj, key, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetClear(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
return CallObjFunc(&SetObject::clear, cx, obj);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
return SetValues(cx, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetValues(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
return CallObjFunc(&SetObject::iterator, cx, SetObject::Values, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
return CallObjFunc(&SetObject::iterator, cx, SetObject::Entries, obj, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::SetForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal)
|
||||
{
|
||||
return forEach("SetForEach", cx, obj, callbackFn, thisVal);
|
||||
}
|
||||
|
@ -98,12 +98,19 @@ class MapObject : public NativeObject {
|
||||
static bool has(JSContext* cx, unsigned argc, Value* vp);
|
||||
static MapObject* create(JSContext* cx);
|
||||
|
||||
static uint32_t size(JSContext* cx, HandleObject obj);
|
||||
static bool get(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
|
||||
static bool has(JSContext* cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
static bool set(JSContext* cx, HandleObject obj, HandleValue key, HandleValue val);
|
||||
static bool clear(JSContext* cx, HandleObject obj);
|
||||
static bool iterator(JSContext* cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
|
||||
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
|
||||
// interfaces, etc.)
|
||||
static uint32_t size(JSContext *cx, HandleObject obj);
|
||||
static bool get(JSContext *cx, HandleObject obj, HandleValue key, MutableHandleValue rval);
|
||||
static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
|
||||
// Set call for public JSAPI exposure. Does not actually return map object
|
||||
// as stated in spec, expects caller to return a value. for instance, with
|
||||
// webidl maplike/setlike, should return interface object.
|
||||
static bool set(JSContext *cx, HandleObject obj, HandleValue key, HandleValue val);
|
||||
static bool clear(JSContext *cx, HandleObject obj);
|
||||
static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
|
||||
|
||||
private:
|
||||
static const JSPropertySpec properties[];
|
||||
@ -145,23 +152,33 @@ class SetObject : public NativeObject {
|
||||
static JSObject* initClass(JSContext* cx, JSObject* obj);
|
||||
static const Class class_;
|
||||
|
||||
static bool keys(JSContext* cx, HandleObject obj, JS::AutoValueVector* keys);
|
||||
static bool values(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool add(JSContext* cx, HandleObject obj, HandleValue key);
|
||||
static bool has(JSContext* cx, unsigned argc, Value* vp);
|
||||
static SetObject* create(JSContext* cx);
|
||||
static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys);
|
||||
static bool values(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool add(JSContext *cx, HandleObject obj, HandleValue key);
|
||||
static bool has(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
// Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
|
||||
// interfaces, etc.)
|
||||
static SetObject* create(JSContext *cx);
|
||||
static uint32_t size(JSContext *cx, HandleObject obj);
|
||||
static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval);
|
||||
static bool clear(JSContext *cx, HandleObject obj);
|
||||
static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter);
|
||||
static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval);
|
||||
|
||||
private:
|
||||
static const JSPropertySpec properties[];
|
||||
static const JSFunctionSpec methods[];
|
||||
static const JSPropertySpec staticProperties[];
|
||||
ValueSet* getData() { return static_cast<ValueSet*>(getPrivate()); }
|
||||
static ValueSet & extract(HandleObject o);
|
||||
static ValueSet & extract(CallReceiver call);
|
||||
static void mark(JSTracer* trc, JSObject* obj);
|
||||
static void finalize(FreeOp* fop, JSObject* obj);
|
||||
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
static bool is(HandleValue v);
|
||||
static bool is(HandleObject o);
|
||||
|
||||
static bool iterator_impl(JSContext* cx, CallArgs args, IteratorKind kind);
|
||||
|
||||
|
@ -112,6 +112,14 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, jsval* vp)
|
||||
if (!JS_SetProperty(cx, info, "arm-simulator", value))
|
||||
return false;
|
||||
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
value = BooleanValue(false);
|
||||
#endif
|
||||
if (!JS_SetProperty(cx, info, "arm64-simulator", value))
|
||||
return false;
|
||||
|
||||
#ifdef MOZ_ASAN
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
|
@ -2475,7 +2475,7 @@ fi
|
||||
dnl Checks for math functions.
|
||||
dnl ========================================================
|
||||
AC_CHECK_LIB(m, sin)
|
||||
AC_CHECK_FUNCS([log2 log1p expm1 sqrt1pm1 acosh asinh atanh trunc cbrt])
|
||||
AC_CHECK_FUNCS([log2 log1p expm1 sqrt1pm1 acosh asinh atanh cbrt])
|
||||
|
||||
|
||||
dnl check for wcrtomb/mbrtowc
|
||||
|
@ -1889,7 +1889,8 @@ InitTypeClasses(JSContext* cx, HandleObject ctypesObj)
|
||||
// Create objects representing the special types void_t and voidptr_t.
|
||||
RootedObject typeObj(cx,
|
||||
CType::DefineBuiltin(cx, ctypesObj, "void_t", CTypeProto, CDataProto, "void",
|
||||
TYPE_void_t, JSVAL_VOID, JSVAL_VOID, &ffi_type_void));
|
||||
TYPE_void_t, JS::UndefinedValue(), JS::UndefinedValue(),
|
||||
&ffi_type_void));
|
||||
if (!typeObj)
|
||||
return false;
|
||||
|
||||
@ -4191,7 +4192,7 @@ CType::GetSafeSize(JSObject* obj, size_t* result)
|
||||
|
||||
jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
|
||||
|
||||
// The "size" property can be an int, a double, or JSVAL_VOID
|
||||
// The "size" property can be an int, a double, or JS::UndefinedValue()
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
if (size.isInt32()) {
|
||||
*result = size.toInt32();
|
||||
@ -4215,9 +4216,10 @@ CType::GetSize(JSObject* obj)
|
||||
|
||||
MOZ_ASSERT(!size.isUndefined());
|
||||
|
||||
// The "size" property can be an int, a double, or JSVAL_VOID
|
||||
// The "size" property can be an int, a double, or JS::UndefinedValue()
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
// For callers who know it can never be JSVAL_VOID, return a size_t directly.
|
||||
// For callers who know it can never be JS::UndefinedValue(), return a size_t
|
||||
// directly.
|
||||
if (size.isInt32())
|
||||
return size.toInt32();
|
||||
return Convert<size_t>(size.toDouble());
|
||||
@ -4230,7 +4232,7 @@ CType::IsSizeDefined(JSObject* obj)
|
||||
|
||||
jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
|
||||
|
||||
// The "size" property can be an int, a double, or JSVAL_VOID
|
||||
// The "size" property can be an int, a double, or JS::UndefinedValue()
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
MOZ_ASSERT(size.isInt32() || size.isDouble() || size.isUndefined());
|
||||
return !size.isUndefined();
|
||||
@ -4709,7 +4711,7 @@ PointerType::ConstructData(JSContext* cx,
|
||||
// The third argument is an optional error sentinel that js-ctypes will return
|
||||
// if an exception is raised while executing the closure. The type must match
|
||||
// the return type of the callback.
|
||||
jsval errVal = JSVAL_VOID;
|
||||
Value errVal = JS::UndefinedValue();
|
||||
if (args.length() == 3)
|
||||
errVal = args[2];
|
||||
|
||||
@ -4930,8 +4932,8 @@ ArrayType::CreateInternal(JSContext* cx,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedValue sizeVal(cx, JSVAL_VOID);
|
||||
RootedValue lengthVal(cx, JSVAL_VOID);
|
||||
RootedValue sizeVal(cx, JS::UndefinedValue());
|
||||
RootedValue lengthVal(cx, JS::UndefinedValue());
|
||||
if (lengthDefined) {
|
||||
// Check for overflow, and convert to an int or double as required.
|
||||
size_t size = length * baseSize;
|
||||
@ -5084,7 +5086,7 @@ ArrayType::GetSafeLength(JSObject* obj, size_t* result)
|
||||
|
||||
jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
|
||||
|
||||
// The "length" property can be an int, a double, or JSVAL_VOID
|
||||
// The "length" property can be an int, a double, or JS::UndefinedValue()
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
if (length.isInt32()) {
|
||||
*result = length.toInt32();
|
||||
@ -5109,9 +5111,10 @@ ArrayType::GetLength(JSObject* obj)
|
||||
|
||||
MOZ_ASSERT(!length.isUndefined());
|
||||
|
||||
// The "length" property can be an int, a double, or JSVAL_VOID
|
||||
// The "length" property can be an int, a double, or JS::UndefinedValue()
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
// For callers who know it can never be JSVAL_VOID, return a size_t directly.
|
||||
// For callers who know it can never be JS::UndefinedValue(), return a size_t
|
||||
// directly.
|
||||
if (length.isInt32())
|
||||
return length.toInt32();
|
||||
return Convert<size_t>(length.toDouble());
|
||||
@ -5441,7 +5444,8 @@ StructType::Create(JSContext* cx, unsigned argc, jsval* vp)
|
||||
// non-instantiable as CData, will have no 'prototype' property, and will
|
||||
// have undefined size and alignment and no ffi_type.
|
||||
RootedObject result(cx, CType::Create(cx, typeProto, nullptr, TYPE_struct,
|
||||
name.toString(), JSVAL_VOID, JSVAL_VOID, nullptr));
|
||||
name.toString(), JS::UndefinedValue(),
|
||||
JS::UndefinedValue(), nullptr));
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
@ -6426,7 +6430,8 @@ FunctionType::CreateInternal(JSContext* cx,
|
||||
|
||||
// Create a new CType object with the common properties and slots.
|
||||
RootedObject typeObj(cx, CType::Create(cx, typeProto, dataProto, TYPE_function,
|
||||
nullptr, JSVAL_VOID, JSVAL_VOID, nullptr));
|
||||
nullptr, JS::UndefinedValue(),
|
||||
JS::UndefinedValue(), nullptr));
|
||||
if (!typeObj)
|
||||
return nullptr;
|
||||
|
||||
@ -7951,7 +7956,7 @@ CDataFinalizer::Methods::Dispose(JSContext* cx, unsigned argc, jsval* vp)
|
||||
MOZ_ASSERT(CType::GetTypeCode(objCodeType) == TYPE_function);
|
||||
|
||||
RootedObject resultType(cx, FunctionType::GetFunctionInfo(objCodeType)->mReturnType);
|
||||
RootedValue result(cx, JSVAL_VOID);
|
||||
RootedValue result(cx, JS::UndefinedValue());
|
||||
|
||||
int errnoStatus;
|
||||
#if defined(XP_WIN)
|
||||
@ -8029,7 +8034,7 @@ CDataFinalizer::Cleanup(CDataFinalizer::Private* p, JSObject* obj)
|
||||
|
||||
JS_SetPrivate(obj, nullptr);
|
||||
for (int i = 0; i < CDATAFINALIZER_SLOTS; ++i) {
|
||||
JS_SetReservedSlot(obj, i, JSVAL_NULL);
|
||||
JS_SetReservedSlot(obj, i, JS::NullValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3472,7 +3472,7 @@ Parser<FullParseHandler>::checkDestructuringObject(BindData<FullParseHandler>* d
|
||||
|
||||
target = member->pn_right;
|
||||
}
|
||||
if (target->isKind(PNK_ASSIGN))
|
||||
if (handler.isUnparenthesizedAssignment(target))
|
||||
target = target->pn_left;
|
||||
|
||||
if (handler.isUnparenthesizedDestructuringPattern(target)) {
|
||||
@ -3510,7 +3510,7 @@ Parser<FullParseHandler>::checkDestructuringArray(BindData<FullParseHandler>* da
|
||||
report(ParseError, false, target, JSMSG_BAD_DESTRUCT_TARGET);
|
||||
return false;
|
||||
}
|
||||
} else if (element->isKind(PNK_ASSIGN)) {
|
||||
} else if (handler.isUnparenthesizedAssignment(element)) {
|
||||
target = element->pn_left;
|
||||
} else {
|
||||
target = element;
|
||||
|
@ -277,7 +277,7 @@ struct InternalGCMethods<Value>
|
||||
if (vp->isObject()) {
|
||||
gc::StoreBuffer* sb = reinterpret_cast<gc::Cell*>(&vp->toObject())->storeBuffer();
|
||||
if (sb)
|
||||
sb->putRelocatableValueFromAnyThread(vp);
|
||||
sb->putValueFromAnyThread(vp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,7 +287,7 @@ struct InternalGCMethods<Value>
|
||||
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
|
||||
JSRuntime* rt = static_cast<js::gc::Cell*>(vp->toGCThing())->runtimeFromAnyThread();
|
||||
JS::shadow::Runtime* shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
shadowRuntime->gcStoreBufferPtr()->removeRelocatableValueFromAnyThread(vp);
|
||||
shadowRuntime->gcStoreBufferPtr()->unputValueFromAnyThread(vp);
|
||||
}
|
||||
|
||||
static void readBarrier(const Value& v) {
|
||||
|
@ -445,14 +445,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
sb.traceWholeCells(mover);
|
||||
TIME_END(traceWholeCells);
|
||||
|
||||
TIME_START(traceRelocatableValues);
|
||||
sb.traceRelocatableValues(mover);
|
||||
TIME_END(traceRelocatableValues);
|
||||
|
||||
TIME_START(traceRelocatableCells);
|
||||
sb.traceRelocatableCells(mover);
|
||||
TIME_END(traceRelocatableCells);
|
||||
|
||||
TIME_START(traceGenericEntries);
|
||||
sb.traceGenericEntries(&mover);
|
||||
TIME_END(traceGenericEntries);
|
||||
@ -557,13 +549,13 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
static bool printedHeader = false;
|
||||
if (!printedHeader) {
|
||||
fprintf(stderr,
|
||||
"MinorGC: Reason PRate Size Time mkVals mkClls mkSlts mkWCll mkRVal mkRCll mkGnrc ckTbls mkRntm mkDbgr clrNOC collct swpABO updtIn runFin frSlts clrSB sweep resize pretnr\n");
|
||||
"MinorGC: Reason PRate Size Time mkVals mkClls mkSlts mkWCll mkGnrc ckTbls mkRntm mkDbgr clrNOC collct swpABO updtIn runFin frSlts clrSB sweep resize pretnr\n");
|
||||
printedHeader = true;
|
||||
}
|
||||
|
||||
#define FMT " %6" PRIu64
|
||||
fprintf(stderr,
|
||||
"MinorGC: %20s %5.1f%% %4d" FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT "\n",
|
||||
"MinorGC: %20s %5.1f%% %4d" FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT "\n",
|
||||
js::gcstats::ExplainReason(reason),
|
||||
promotionRate * 100,
|
||||
numActiveChunks_,
|
||||
@ -573,8 +565,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
TIME_TOTAL(traceCells),
|
||||
TIME_TOTAL(traceSlots),
|
||||
TIME_TOTAL(traceWholeCells),
|
||||
TIME_TOTAL(traceRelocatableValues),
|
||||
TIME_TOTAL(traceRelocatableCells),
|
||||
TIME_TOTAL(traceGenericEntries),
|
||||
TIME_TOTAL(checkHashTables),
|
||||
TIME_TOTAL(markRuntime),
|
||||
|
@ -44,8 +44,6 @@ StoreBuffer::enable()
|
||||
!bufferCell.init() ||
|
||||
!bufferSlot.init() ||
|
||||
!bufferWholeCell.init() ||
|
||||
!bufferRelocVal.init() ||
|
||||
!bufferRelocCell.init() ||
|
||||
!bufferGeneric.init())
|
||||
{
|
||||
return false;
|
||||
@ -79,8 +77,6 @@ StoreBuffer::clear()
|
||||
bufferCell.clear();
|
||||
bufferSlot.clear();
|
||||
bufferWholeCell.clear();
|
||||
bufferRelocVal.clear();
|
||||
bufferRelocCell.clear();
|
||||
bufferGeneric.clear();
|
||||
|
||||
return true;
|
||||
@ -104,8 +100,6 @@ StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSi
|
||||
sizes->storeBufferCells += bufferCell.sizeOfExcludingThis(mallocSizeOf);
|
||||
sizes->storeBufferSlots += bufferSlot.sizeOfExcludingThis(mallocSizeOf);
|
||||
sizes->storeBufferWholeCells += bufferWholeCell.sizeOfExcludingThis(mallocSizeOf);
|
||||
sizes->storeBufferRelocVals += bufferRelocVal.sizeOfExcludingThis(mallocSizeOf);
|
||||
sizes->storeBufferRelocCells += bufferRelocCell.sizeOfExcludingThis(mallocSizeOf);
|
||||
sizes->storeBufferGenerics += bufferGeneric.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
|
@ -381,8 +381,6 @@ class StoreBuffer
|
||||
MonoTypeBuffer<CellPtrEdge> bufferCell;
|
||||
MonoTypeBuffer<SlotsEdge> bufferSlot;
|
||||
MonoTypeBuffer<WholeCellEdges> bufferWholeCell;
|
||||
MonoTypeBuffer<ValueEdge> bufferRelocVal;
|
||||
MonoTypeBuffer<CellPtrEdge> bufferRelocCell;
|
||||
GenericBuffer bufferGeneric;
|
||||
bool cancelIonCompilations_;
|
||||
|
||||
@ -395,10 +393,9 @@ class StoreBuffer
|
||||
|
||||
public:
|
||||
explicit StoreBuffer(JSRuntime* rt, const Nursery& nursery)
|
||||
: bufferVal(), bufferCell(), bufferSlot(), bufferWholeCell(),
|
||||
bufferRelocVal(), bufferRelocCell(), bufferGeneric(), cancelIonCompilations_(false),
|
||||
runtime_(rt), nursery_(nursery), aboutToOverflow_(false), enabled_(false),
|
||||
mEntered(false)
|
||||
: bufferVal(), bufferCell(), bufferSlot(), bufferWholeCell(), bufferGeneric(),
|
||||
cancelIonCompilations_(false), runtime_(rt), nursery_(nursery), aboutToOverflow_(false),
|
||||
enabled_(false), mEntered(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -414,8 +411,10 @@ class StoreBuffer
|
||||
bool cancelIonCompilations() const { return cancelIonCompilations_; }
|
||||
|
||||
/* Insert a single edge into the buffer/remembered set. */
|
||||
void putValueFromAnyThread(JS::Value* valuep) { putFromAnyThread(bufferVal, ValueEdge(valuep)); }
|
||||
void putValueFromAnyThread(JS::Value* vp) { putFromAnyThread(bufferVal, ValueEdge(vp)); }
|
||||
void unputValueFromAnyThread(JS::Value* vp) { unputFromAnyThread(bufferVal, ValueEdge(vp)); }
|
||||
void putCellFromAnyThread(Cell** cellp) { putFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
|
||||
void unputCellFromAnyThread(Cell** cellp) { unputFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
|
||||
void putSlotFromAnyThread(NativeObject* obj, int kind, int32_t start, int32_t count) {
|
||||
putFromAnyThread(bufferSlot, SlotsEdge(obj, kind, start, count));
|
||||
}
|
||||
@ -424,20 +423,6 @@ class StoreBuffer
|
||||
putFromMainThread(bufferWholeCell, WholeCellEdges(cell));
|
||||
}
|
||||
|
||||
/* Insert or update a single edge in the Relocatable buffer. */
|
||||
void putRelocatableValueFromAnyThread(JS::Value* valuep) {
|
||||
putFromAnyThread(bufferRelocVal, ValueEdge(valuep));
|
||||
}
|
||||
void removeRelocatableValueFromAnyThread(JS::Value* valuep) {
|
||||
unputFromAnyThread(bufferRelocVal, ValueEdge(valuep));
|
||||
}
|
||||
void putRelocatableCellFromAnyThread(Cell** cellp) {
|
||||
putFromAnyThread(bufferRelocCell, CellPtrEdge(cellp));
|
||||
}
|
||||
void removeRelocatableCellFromAnyThread(Cell** cellp) {
|
||||
unputFromAnyThread(bufferRelocCell, CellPtrEdge(cellp));
|
||||
}
|
||||
|
||||
/* Insert an entry into the generic buffer. */
|
||||
template <typename T>
|
||||
void putGeneric(const T& t) { putFromAnyThread(bufferGeneric, t);}
|
||||
@ -457,20 +442,11 @@ class StoreBuffer
|
||||
void traceCells(TenuringTracer& mover) { bufferCell.trace(this, mover); }
|
||||
void traceSlots(TenuringTracer& mover) { bufferSlot.trace(this, mover); }
|
||||
void traceWholeCells(TenuringTracer& mover) { bufferWholeCell.trace(this, mover); }
|
||||
void traceRelocatableValues(TenuringTracer& mover) { bufferRelocVal.trace(this, mover); }
|
||||
void traceRelocatableCells(TenuringTracer& mover) { bufferRelocCell.trace(this, mover); }
|
||||
void traceGenericEntries(JSTracer *trc) { bufferGeneric.trace(this, trc); }
|
||||
|
||||
/* For use by our owned buffers and for testing. */
|
||||
void setAboutToOverflow();
|
||||
|
||||
/* For jit access to the raw buffer. */
|
||||
void oolSinkStoresForWholeCellBuffer() { bufferWholeCell.sinkStores(this); }
|
||||
void* addressOfWholeCellBufferPointer() const { return (void*)&bufferWholeCell.insert_; }
|
||||
void* addressOfWholeCellBufferEnd() const {
|
||||
return (void*)(bufferWholeCell.buffer_ + bufferWholeCell.NumBufferEntries);
|
||||
}
|
||||
|
||||
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSizes* sizes);
|
||||
};
|
||||
|
||||
|
@ -120,6 +120,12 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
||||
// registers we need.
|
||||
masm.bind(&entry_label_);
|
||||
|
||||
#ifdef JS_CODEGEN_ARM64
|
||||
// ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
|
||||
MOZ_ASSERT(!masm.GetStackPointer64().Is(sp));
|
||||
masm.moveStackPtrTo(masm.getStackPointer());
|
||||
#endif
|
||||
|
||||
// Push non-volatile registers which might be modified by jitcode.
|
||||
size_t pushedNonVolatileRegisters = 0;
|
||||
for (GeneralRegisterForwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter) {
|
||||
@ -387,7 +393,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
||||
|
||||
// Save registers before calling C function
|
||||
LiveGeneralRegisterSet volatileRegs(GeneralRegisterSet::Volatile());
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
|
||||
volatileRegs.add(Register::FromCode(Registers::lr));
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
volatileRegs.add(Register::FromCode(Registers::ra));
|
||||
|
@ -1,5 +1,7 @@
|
||||
// Test that new.target is acceptably usable in RematerializedFrames.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
load(libdir + "jitopts.js");
|
||||
|
||||
if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
|
||||
|
@ -1,5 +1,7 @@
|
||||
// Test that new.target is acceptably usable in RematerializedFrames.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
load(libdir + "jitopts.js");
|
||||
|
||||
if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/AtomicOperations-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/AtomicOperations-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/AtomicOperations-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
@ -19,4 +21,4 @@
|
||||
# error "Atomic operations must be defined for this platform"
|
||||
#endif
|
||||
|
||||
#endif // jit_AtomicOperations_inl_h
|
||||
#endif // jit_AtomicOperations_inl_h
|
||||
|
@ -18,6 +18,8 @@
|
||||
# include "jit/x64/CodeGenerator-x64.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/CodeGenerator-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/CodeGenerator-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/CodeGenerator-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/Assembler-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/Assembler-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/Assembler-mips.h"
|
||||
#endif
|
||||
|
@ -11,11 +11,13 @@
|
||||
|
||||
#if defined(JS_SIMULATOR_ARM)
|
||||
#include "jit/arm/Simulator-arm.h"
|
||||
#elif defined(JS_SIMULATOR_ARM64)
|
||||
# include "jit/arm64/vixl/Simulator-vixl.h"
|
||||
#elif defined(JS_SIMULATOR_MIPS)
|
||||
#include "jit/mips/Simulator-mips.h"
|
||||
#endif
|
||||
|
||||
#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS)
|
||||
#ifdef JS_SIMULATOR
|
||||
// Call into cross-jitted code by following the ABI of the simulated architecture.
|
||||
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
|
||||
(js::jit::Simulator::Current()->call( \
|
||||
|
@ -2593,6 +2593,12 @@ MachineState::FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray&
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Int32x4), &fpregs[i]);
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Float32x4), &fpregs[i]);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Single), &fpregs[i]);
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegisters::Double), &fpregs[i]);
|
||||
}
|
||||
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
MOZ_CRASH();
|
||||
#else
|
||||
|
@ -1825,6 +1825,8 @@ LAllocation::toRegister() const
|
||||
# include "jit/x86-shared/LIR-x86-shared.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/LIR-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/LIR-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/LIR-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
|
@ -359,6 +359,8 @@
|
||||
# include "jit/x64/LOpcodes-x64.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/LOpcodes-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/LOpcodes-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/LOpcodes-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
|
@ -17,6 +17,8 @@
|
||||
# include "jit/x64/Lowering-x64.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/Lowering-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/Lowering-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/Lowering-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
|
@ -1594,8 +1594,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
||||
regs.take(bailoutInfo);
|
||||
|
||||
// Reset SP to the point where clobbering starts.
|
||||
loadPtr(Address(bailoutInfo, offsetof(BaselineBailoutInfo, incomingStack)),
|
||||
BaselineStackReg);
|
||||
loadStackPtr(Address(bailoutInfo, offsetof(BaselineBailoutInfo, incomingStack)));
|
||||
|
||||
Register copyCur = regs.takeAny();
|
||||
Register copyEnd = regs.takeAny();
|
||||
@ -1610,7 +1609,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
||||
bind(©Loop);
|
||||
branchPtr(Assembler::BelowOrEqual, copyCur, copyEnd, &endOfCopy);
|
||||
subPtr(Imm32(4), copyCur);
|
||||
subPtr(Imm32(4), BaselineStackReg);
|
||||
subFromStackPtr(Imm32(4));
|
||||
load32(Address(copyCur, 0), temp);
|
||||
store32(temp, Address(BaselineStackReg, 0));
|
||||
jump(©Loop);
|
||||
@ -2510,9 +2509,12 @@ MacroAssembler::MacroAssembler(JSContext* cx, IonScript* ion,
|
||||
jitContext_.emplace(cx, (js::jit::TempAllocator*)nullptr);
|
||||
alloc_.emplace(cx);
|
||||
moveResolver_.setAllocator(*jitContext_->temp);
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
initWithAllocator();
|
||||
m_buffer.id = GetJitContext()->getNextAssemblerId();
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
initWithAllocator();
|
||||
armbuffer_.id = GetJitContext()->getNextAssemblerId();
|
||||
#endif
|
||||
if (ion) {
|
||||
setFramePushed(ion->frameSize());
|
||||
@ -2707,12 +2709,12 @@ MacroAssembler::freeStack(uint32_t amount)
|
||||
{
|
||||
MOZ_ASSERT(amount <= framePushed_);
|
||||
if (amount)
|
||||
addPtr(Imm32(amount), StackPointer);
|
||||
addToStackPtr(Imm32(amount));
|
||||
framePushed_ -= amount;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::freeStack(Register amount)
|
||||
{
|
||||
addPtr(amount, StackPointer);
|
||||
addToStackPtr(amount);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
# include "jit/x64/MacroAssembler-x64.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/MacroAssembler-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/MacroAssembler-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/MacroAssembler-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
@ -44,6 +46,8 @@
|
||||
# define ONLY_X86_X64
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# define ONLY_X86_X64 = delete
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# define ONLY_X86_X64 = delete
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# define ONLY_X86_X64 = delete
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
@ -233,9 +237,13 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
}
|
||||
|
||||
moveResolver_.setAllocator(*jcx->temp);
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
initWithAllocator();
|
||||
m_buffer.id = jcx->getNextAssemblerId();
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
initWithAllocator();
|
||||
armbuffer_.id = jcx->getNextAssemblerId();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -250,9 +258,12 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
: emitProfilingInstrumentation_(false),
|
||||
framePushed_(0)
|
||||
{
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
initWithAllocator();
|
||||
m_buffer.id = 0;
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
initWithAllocator();
|
||||
armbuffer_.id = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -572,7 +583,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
}
|
||||
#elif defined(JS_PUNBOX64)
|
||||
if (dest.valueReg() != JSReturnReg)
|
||||
movq(JSReturnReg, dest.valueReg());
|
||||
mov(JSReturnReg, dest.valueReg());
|
||||
#else
|
||||
#error "Bad architecture"
|
||||
#endif
|
||||
|
@ -11,6 +11,8 @@
|
||||
# include "jit/x86-shared/MoveEmitter-x86-shared.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/MoveEmitter-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/MoveEmitter-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/MoveEmitter-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
|
@ -375,18 +375,20 @@ class jit::UniqueTrackedTypes
|
||||
{ }
|
||||
|
||||
bool init() { return map_.init(); }
|
||||
bool getIndexOf(TypeSet::Type ty, uint8_t* indexp);
|
||||
bool getIndexOf(JSContext* cx, TypeSet::Type ty, uint8_t* indexp);
|
||||
|
||||
uint32_t count() const { MOZ_ASSERT(map_.count() == list_.length()); return list_.length(); }
|
||||
bool enumerate(TypeSet::TypeList* types) const;
|
||||
};
|
||||
|
||||
bool
|
||||
UniqueTrackedTypes::getIndexOf(TypeSet::Type ty, uint8_t* indexp)
|
||||
UniqueTrackedTypes::getIndexOf(JSContext* cx, TypeSet::Type ty, uint8_t* indexp)
|
||||
{
|
||||
// For now, tracking of nursery singleton objects is not supported.
|
||||
if (ty.isSingletonUnchecked() && IsInsideNursery(ty.singleton()))
|
||||
ty = TypeSet::UnknownType();
|
||||
// FIXME bug 1176511. It is unduly onerous to make nursery things work
|
||||
// correctly as keys of hash tables. Until then, since TypeSet::Types may
|
||||
// be in the nursery, we evict the nursery before tracking types.
|
||||
cx->runtime()->gc.evictNursery();
|
||||
MOZ_ASSERT_IF(ty.isSingletonUnchecked(), !IsInsideNursery(ty.singleton()));
|
||||
|
||||
TypesMap::AddPtr p = map_.lookupForAdd(ty);
|
||||
if (p) {
|
||||
@ -600,15 +602,15 @@ OptimizationAttempt::writeCompact(CompactBufferWriter& writer) const
|
||||
}
|
||||
|
||||
bool
|
||||
OptimizationTypeInfo::writeCompact(CompactBufferWriter& writer,
|
||||
UniqueTrackedTypes& uniqueTypes) const
|
||||
OptimizationTypeInfo::writeCompact(JSContext* cx, CompactBufferWriter& writer,
|
||||
UniqueTrackedTypes& uniqueTypes) const
|
||||
{
|
||||
writer.writeUnsigned((uint32_t) site_);
|
||||
writer.writeUnsigned((uint32_t) mirType_);
|
||||
writer.writeUnsigned(types_.length());
|
||||
for (uint32_t i = 0; i < types_.length(); i++) {
|
||||
uint8_t index;
|
||||
if (!uniqueTypes.getIndexOf(types_[i], &index))
|
||||
if (!uniqueTypes.getIndexOf(cx, types_[i], &index))
|
||||
return false;
|
||||
writer.writeByte(index);
|
||||
}
|
||||
@ -954,7 +956,7 @@ jit::WriteIonTrackedOptimizationsTable(JSContext* cx, CompactBufferWriter& write
|
||||
return false;
|
||||
|
||||
for (const OptimizationTypeInfo* t = v->begin(); t != v->end(); t++) {
|
||||
if (!t->writeCompact(writer, uniqueTypes))
|
||||
if (!t->writeCompact(cx, writer, uniqueTypes))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,8 @@ class OptimizationTypeInfo
|
||||
|
||||
HashNumber hash() const;
|
||||
|
||||
bool writeCompact(CompactBufferWriter& writer, UniqueTrackedTypes& uniqueTypes) const;
|
||||
bool writeCompact(JSContext* cx, CompactBufferWriter& writer,
|
||||
UniqueTrackedTypes& uniqueTypes) const;
|
||||
};
|
||||
|
||||
typedef Vector<OptimizationTypeInfo, 1, JitAllocPolicy> TempOptimizationTypeInfoVector;
|
||||
|
@ -278,6 +278,10 @@ class RegisterAllocator
|
||||
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
|
||||
allRegisters_.take(AnyRegister(HeapReg));
|
||||
allRegisters_.take(AnyRegister(GlobalReg));
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
allRegisters_.take(AnyRegister(HeapReg));
|
||||
allRegisters_.take(AnyRegister(HeapLenReg));
|
||||
allRegisters_.take(AnyRegister(GlobalReg));
|
||||
#endif
|
||||
} else {
|
||||
if (FramePointer != InvalidReg && mir->instrumentedProfiling())
|
||||
|
@ -14,6 +14,8 @@
|
||||
# include "jit/x86-shared/Architecture-x86-shared.h"
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
# include "jit/arm/Architecture-arm.h"
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
# include "jit/arm64/Architecture-arm64.h"
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
# include "jit/mips/Architecture-mips.h"
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
@ -42,8 +44,7 @@ struct Register {
|
||||
Register r = { Encoding(code) };
|
||||
return r;
|
||||
}
|
||||
Code code() const {
|
||||
MOZ_ASSERT(Code(reg_) < Registers::Total);
|
||||
MOZ_CONSTEXPR Code code() const {
|
||||
return Code(reg_);
|
||||
}
|
||||
Encoding encoding() const {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user