Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-06-30 14:31:00 +02:00
commit fababd0f52
571 changed files with 6450 additions and 1433 deletions

View File

@ -696,6 +696,7 @@
#ifdef MOZ_DEBUG
@RESPATH@/components/TestInterfaceJS.js
@RESPATH@/components/TestInterfaceJS.manifest
@RESPATH@/components/TestInterfaceJSMaplike.js
#endif
@RESPATH@/components/PACGenerator.js

View File

@ -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);

View File

@ -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();

View File

@ -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.

View File

@ -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]

View File

@ -623,6 +623,7 @@
#ifdef MOZ_DEBUG
@RESPATH@/components/TestInterfaceJS.js
@RESPATH@/components/TestInterfaceJS.manifest
@RESPATH@/components/TestInterfaceJSMaplike.js
#endif
@RESPATH@/components/PACGenerator.js

View File

@ -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")) {

View File

@ -4585,8 +4585,7 @@ nsDocShell::GetDocument()
nsPIDOMWindow*
nsDocShell::GetWindow()
{
NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
return mScriptGlobal;
return NS_SUCCEEDED(EnsureScriptEnvironment()) ? mScriptGlobal : nullptr;
}
NS_IMETHODIMP

View File

@ -613,7 +613,7 @@ void
Link::CreateSearchParamsIfNeeded()
{
if (!mSearchParams) {
mSearchParams = new URLSearchParams(this);
mSearchParams = new URLSearchParams(this, this);
UpdateURLSearchParams();
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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()
{

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -1308,12 +1308,9 @@ DOMInterfaces = {
'implicitJSContext' : [ 'undo', 'redo', 'transact' ],
},
'URL' : [{
'wrapperCache': False,
},
'URL' : [{},
{
'workers': True,
'wrapperCache': False,
}],
'VRDevice': {

View File

@ -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.

View File

@ -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

View File

@ -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']:

View File

@ -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

View 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)

View File

@ -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}

View 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])

View 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);
}
}
}

View 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

View 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);
}
}
}

View 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

View 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;
}
}
}

View 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

View 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;
}
}
}

View 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

View File

@ -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

View File

@ -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

View File

@ -17,6 +17,7 @@ Library('dombindings_test_s')
EXTRA_COMPONENTS += [
'TestInterfaceJS.js',
'TestInterfaceJS.manifest',
'TestInterfaceJSMaplike.js'
]
MOCHITEST_MANIFESTS += ['mochitest.ini']

View 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>

View 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>

View File

@ -105,6 +105,11 @@ private:
void UpdateMustKeepAlive();
bool IsCertainlyAliveForCC() const override
{
return mIsKeptAlive;
}
nsRefPtr<BroadcastChannelChild> mActor;
nsTArray<nsRefPtr<BroadcastChannelMessage>> mPendingMessages;

View File

@ -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});

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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);
}

View File

@ -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 :

View File

@ -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;
}

View File

@ -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 -->

View 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>;
};

View File

@ -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']:

View File

@ -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();
}
}

View File

@ -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

View File

@ -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 {

View File

@ -251,7 +251,7 @@ public:
NullResponseText()
{
mStateData.mResponseText.SetIsVoid(true);
mStateData.mResponse = JSVAL_NULL;
mStateData.mResponse.setNull();
}
bool MozAnon() const

View File

@ -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);

View File

@ -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)
{ }

View File

@ -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)
{}

View File

@ -20,7 +20,7 @@ class TestDataStructuresSub :
public PTestDataStructuresSubChild
{
public:
TestDataStructuresSub(uint32_t i) : mI(i)
explicit TestDataStructuresSub(uint32_t i) : mI(i)
{ }
virtual ~TestDataStructuresSub()
{ }

View File

@ -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)
{}

View File

@ -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)
{
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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()));

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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"]
};

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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),

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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));

View File

@ -1,5 +1,7 @@
// Test that new.target is acceptably usable in RematerializedFrames.
gczeal(0);
load(libdir + "jitopts.js");
if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))

View File

@ -1,5 +1,7 @@
// Test that new.target is acceptably usable in RematerializedFrames.
gczeal(0);
load(libdir + "jitopts.js");
if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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( \

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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(&copyLoop);
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(&copyLoop);
@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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())

View File

@ -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