mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
de062041d4
@ -396,7 +396,10 @@ SingleAccIterator::Next()
|
||||
{
|
||||
nsRefPtr<Accessible> nextAcc;
|
||||
mAcc.swap(nextAcc);
|
||||
return (nextAcc && !nextAcc->IsDefunct()) ? nextAcc : nullptr;
|
||||
if (!nextAcc || nextAcc->IsDefunct()) {
|
||||
return nullptr;
|
||||
}
|
||||
return nextAcc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -486,7 +486,10 @@ HTMLTextFieldAccessible::IsWidget() const
|
||||
Accessible*
|
||||
HTMLTextFieldAccessible::ContainerWidget() const
|
||||
{
|
||||
return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nullptr;
|
||||
if (!mParent || mParent->Role() != roles::AUTOCOMPLETE) {
|
||||
return nullptr;
|
||||
}
|
||||
return mParent;
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,10 +32,14 @@ this.ContentWebRTC = {
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
Services.obs.removeObserver(handleRequest, "getUserMedia:request");
|
||||
Services.obs.removeObserver(handleGUMRequest, "getUserMedia:request");
|
||||
Services.obs.removeObserver(handlePCRequest, "PeerConnection:request");
|
||||
Services.obs.removeObserver(updateIndicators, "recording-device-events");
|
||||
Services.obs.removeObserver(removeBrowserSpecificIndicator, "recording-window-ended");
|
||||
Services.obs.removeObserver(processShutdown, "content-child-shutdown");
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
|
||||
Services.obs.removeObserver(processShutdown, "content-child-shutdown");
|
||||
|
||||
this._initialized = false;
|
||||
},
|
||||
|
||||
|
@ -747,6 +747,7 @@ media/stagefright/foundation/hexdump.h
|
||||
media/stagefright/MediaBuffer.h
|
||||
media/stagefright/MediaBufferGroup.h
|
||||
media/stagefright/MediaCodec.h
|
||||
media/stagefright/MediaCodecSource.h
|
||||
media/stagefright/MediaDefs.h
|
||||
media/stagefright/MediaErrors.h
|
||||
media/stagefright/MediaExtractor.h
|
||||
|
@ -4338,7 +4338,10 @@ nsDocShell::GetDocument()
|
||||
nsPIDOMWindow*
|
||||
nsDocShell::GetWindow()
|
||||
{
|
||||
return NS_SUCCEEDED(EnsureScriptEnvironment()) ? mScriptGlobal : nullptr;
|
||||
if (NS_FAILED(EnsureScriptEnvironment())) {
|
||||
return nullptr;
|
||||
}
|
||||
return mScriptGlobal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -210,25 +210,19 @@ DOMImplementation::CreateHTMLDocument(const nsAString& aTitle,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
|
||||
|
||||
nsCOMPtr<nsIContent> root;
|
||||
rv = doc->CreateElem(NS_LITERAL_STRING("html"), nullptr, kNameSpaceID_XHTML,
|
||||
getter_AddRefs(root));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<Element> root = doc->CreateElem(NS_LITERAL_STRING("html"), nullptr,
|
||||
kNameSpaceID_XHTML);
|
||||
rv = doc->AppendChildTo(root, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIContent> head;
|
||||
rv = doc->CreateElem(NS_LITERAL_STRING("head"), nullptr, kNameSpaceID_XHTML,
|
||||
getter_AddRefs(head));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<Element> head = doc->CreateElem(NS_LITERAL_STRING("head"), nullptr,
|
||||
kNameSpaceID_XHTML);
|
||||
rv = root->AppendChildTo(head, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!DOMStringIsNull(aTitle)) {
|
||||
nsCOMPtr<nsIContent> title;
|
||||
rv = doc->CreateElem(NS_LITERAL_STRING("title"), nullptr,
|
||||
kNameSpaceID_XHTML, getter_AddRefs(title));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<Element> title = doc->CreateElem(NS_LITERAL_STRING("title"),
|
||||
nullptr, kNameSpaceID_XHTML);
|
||||
rv = head->AppendChildTo(title, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -239,10 +233,8 @@ DOMImplementation::CreateHTMLDocument(const nsAString& aTitle,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> body;
|
||||
rv = doc->CreateElem(NS_LITERAL_STRING("body"), nullptr, kNameSpaceID_XHTML,
|
||||
getter_AddRefs(body));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<Element> body = doc->CreateElem(NS_LITERAL_STRING("body"), nullptr,
|
||||
kNameSpaceID_XHTML);
|
||||
rv = root->AppendChildTo(body, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -84,7 +84,10 @@ public:
|
||||
File* IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mFiles.Length();
|
||||
return aFound ? mFiles.ElementAt(aIndex) : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mFiles.ElementAt(aIndex);
|
||||
}
|
||||
|
||||
uint32_t Length()
|
||||
|
@ -706,7 +706,7 @@ ImportManager::AddLoaderWithNewURI(ImportLoader* aLoader, nsIURI* aNewURI)
|
||||
mImports.Put(aNewURI, aLoader);
|
||||
}
|
||||
|
||||
nsRefPtr<ImportLoader> ImportManager::GetNearestPredecessor(nsINode* aNode)
|
||||
ImportLoader* ImportManager::GetNearestPredecessor(nsINode* aNode)
|
||||
{
|
||||
// Return the previous link if there is any in the same document.
|
||||
nsIDocument* doc = aNode->OwnerDoc();
|
||||
|
@ -265,7 +265,7 @@ public:
|
||||
|
||||
// It finds the predecessor for an import link node that runs its
|
||||
// scripts the latest among its predecessors.
|
||||
nsRefPtr<ImportLoader> GetNearestPredecessor(nsINode* aNode);
|
||||
ImportLoader* GetNearestPredecessor(nsINode* aNode);
|
||||
|
||||
private:
|
||||
ImportMap mImports;
|
||||
|
@ -5447,13 +5447,8 @@ nsIDocument::CreateElement(const nsAString& aTagName, ErrorResult& rv)
|
||||
nsContentUtils::ASCIIToLower(aTagName, lcTagName);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
rv = CreateElem(needsLowercase ? lcTagName : aTagName,
|
||||
nullptr, mDefaultElementType, getter_AddRefs(content));
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
return dont_AddRef(content.forget().take()->AsElement());
|
||||
return CreateElem(needsLowercase ? lcTagName : aTagName, nullptr,
|
||||
mDefaultElementType);
|
||||
}
|
||||
|
||||
void
|
||||
@ -5797,13 +5792,10 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
|
||||
|
||||
nsDependentAtomString localName(definition->mLocalName);
|
||||
|
||||
nsCOMPtr<nsIContent> newElement;
|
||||
nsresult rv = document->CreateElem(localName, nullptr,
|
||||
definition->mNamespaceID,
|
||||
getter_AddRefs(newElement));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
nsCOMPtr<Element> element =
|
||||
document->CreateElem(localName, nullptr, definition->mNamespaceID);
|
||||
NS_ENSURE_TRUE(element, true);
|
||||
|
||||
nsCOMPtr<Element> element = do_QueryInterface(newElement);
|
||||
if (definition->mLocalName != typeAtom) {
|
||||
// This element is a custom element by extension, thus we need to
|
||||
// do some special setup. For non-extended custom elements, this happens
|
||||
@ -5811,7 +5803,7 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
|
||||
document->SetupCustomElement(element, definition->mNamespaceID, &elemName);
|
||||
}
|
||||
|
||||
rv = nsContentUtils::WrapNative(aCx, newElement, newElement, args.rval());
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
return true;
|
||||
@ -8600,9 +8592,9 @@ nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix, int32_t aNamespaceID,
|
||||
nsIContent **aResult)
|
||||
already_AddRefed<Element>
|
||||
nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix,
|
||||
int32_t aNamespaceID)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsAutoString qName;
|
||||
@ -8621,19 +8613,16 @@ nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix, int32_t aNamesp
|
||||
"check caller.");
|
||||
#endif
|
||||
|
||||
*aResult = nullptr;
|
||||
|
||||
nsRefPtr<mozilla::dom::NodeInfo> nodeInfo;
|
||||
mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID,
|
||||
nsIDOMNode::ELEMENT_NODE,
|
||||
getter_AddRefs(nodeInfo));
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ENSURE_TRUE(nodeInfo, nullptr);
|
||||
|
||||
nsCOMPtr<Element> element;
|
||||
nsresult rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
|
||||
NOT_FROM_PARSER);
|
||||
element.forget(aResult);
|
||||
return rv;
|
||||
return NS_SUCCEEDED(rv) ? element.forget() : nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1011,9 +1011,9 @@ public:
|
||||
|
||||
virtual nsresult Init();
|
||||
|
||||
virtual nsresult CreateElem(const nsAString& aName, nsIAtom *aPrefix,
|
||||
int32_t aNamespaceID,
|
||||
nsIContent **aResult) override;
|
||||
virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
|
||||
nsIAtom* aPrefix,
|
||||
int32_t aNamespaceID) override;
|
||||
|
||||
virtual void Sanitize() override;
|
||||
|
||||
|
@ -696,7 +696,10 @@ ShadowRoot *
|
||||
nsGenericDOMDataNode::GetContainingShadow() const
|
||||
{
|
||||
nsDataSlots *slots = GetExistingDataSlots();
|
||||
return slots ? slots->mContainingShadow : nullptr;
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
return slots->mContainingShadow;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -152,8 +152,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x6d18ec0b, 0x1f68, 0x4ae6, \
|
||||
{ 0x8b, 0x3d, 0x8d, 0x7d, 0x8b, 0x8e, 0x28, 0xd4 } }
|
||||
{ 0x292450a1, 0x285e, 0x4a09, \
|
||||
{ 0x9a, 0xf9, 0x61, 0xf9, 0xb1, 0xbd, 0x27, 0xcc } }
|
||||
|
||||
// Enum for requesting a particular type of document when creating a doc
|
||||
enum DocumentFlavor {
|
||||
@ -1372,10 +1372,11 @@ public:
|
||||
|
||||
/**
|
||||
* Create an element with the specified name, prefix and namespace ID.
|
||||
* Returns null if element name parsing failed.
|
||||
*/
|
||||
virtual nsresult CreateElem(const nsAString& aName, nsIAtom *aPrefix,
|
||||
int32_t aNamespaceID,
|
||||
nsIContent** aResult) = 0;
|
||||
virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
|
||||
nsIAtom* aPrefix,
|
||||
int32_t aNamespaceID) = 0;
|
||||
|
||||
/**
|
||||
* Get the security info (i.e. SSL state etc) that the document got
|
||||
|
@ -264,8 +264,10 @@ nsMimeType::GetDescription(nsString& aRetval) const
|
||||
nsPluginElement*
|
||||
nsMimeType::GetEnabledPlugin() const
|
||||
{
|
||||
return (mPluginElement && mPluginElement->PluginTag()->IsEnabled()) ?
|
||||
mPluginElement : nullptr;
|
||||
if (!mPluginElement || !mPluginElement->PluginTag()->IsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mPluginElement;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -175,7 +175,11 @@ nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
|
||||
|
||||
aFound = aIndex < mPlugins.Length();
|
||||
|
||||
return aFound ? mPlugins[aIndex] : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mPlugins[aIndex];
|
||||
}
|
||||
|
||||
void
|
||||
@ -391,7 +395,11 @@ nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
|
||||
|
||||
aFound = aIndex < mMimeTypes.Length();
|
||||
|
||||
return aFound ? mMimeTypes[aIndex] : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mMimeTypes[aIndex];
|
||||
}
|
||||
|
||||
nsMimeType*
|
||||
|
@ -113,6 +113,7 @@ def memoize(fn):
|
||||
grows without bound.
|
||||
"""
|
||||
cache = {}
|
||||
|
||||
@functools.wraps(fn)
|
||||
def wrapper(arg):
|
||||
retval = cache.get(arg)
|
||||
@ -121,6 +122,7 @@ def memoize(fn):
|
||||
return retval
|
||||
return wrapper
|
||||
|
||||
|
||||
@memoize
|
||||
def dedent(s):
|
||||
"""
|
||||
@ -595,6 +597,7 @@ def InterfacePrototypeObjectProtoGetter(descriptor):
|
||||
|
||||
return (protoGetter, protoHandleGetter)
|
||||
|
||||
|
||||
class CGPrototypeJSClass(CGThing):
|
||||
def __init__(self, descriptor, properties):
|
||||
CGThing.__init__(self)
|
||||
@ -656,6 +659,7 @@ def NeedsGeneratedHasInstance(descriptor):
|
||||
assert descriptor.interface.hasInterfaceObject()
|
||||
return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential()
|
||||
|
||||
|
||||
def InterfaceObjectProtoGetter(descriptor):
|
||||
"""
|
||||
Returns a tuple with two elements:
|
||||
@ -679,6 +683,7 @@ def InterfaceObjectProtoGetter(descriptor):
|
||||
protoHandleGetter = None
|
||||
return (protoGetter, protoHandleGetter)
|
||||
|
||||
|
||||
class CGInterfaceObjectJSClass(CGThing):
|
||||
def __init__(self, descriptor, properties):
|
||||
CGThing.__init__(self)
|
||||
@ -1020,7 +1025,7 @@ class CGHeaders(CGWrapper):
|
||||
implementationIncludes |= set(self.getDeclarationFilename(i) for i in
|
||||
interfacesImplementingSelf)
|
||||
|
||||
# Grab the includes for the things that involve XPCOM interfaces
|
||||
# Grab the includes for the things that involve XPCOM interfaces
|
||||
hasInstanceIncludes = set("nsIDOM" + d.interface.identifier.name + ".h" for d
|
||||
in descriptors if
|
||||
d.interface.hasInterfaceObject() and
|
||||
@ -1214,6 +1219,7 @@ def SortedDictValues(d):
|
||||
"""
|
||||
return [v for k, v in sorted(d.items())]
|
||||
|
||||
|
||||
def UnionsForFile(config, webIDLFile):
|
||||
"""
|
||||
Returns a list of tuples each containing two elements (type and descriptor)
|
||||
@ -1223,6 +1229,7 @@ def UnionsForFile(config, webIDLFile):
|
||||
"""
|
||||
return config.unionsPerFilename.get(webIDLFile, [])
|
||||
|
||||
|
||||
def UnionTypes(unionTypes, config):
|
||||
"""
|
||||
The unionTypes argument should be a list of tuples, each containing two
|
||||
@ -1322,6 +1329,7 @@ def UnionTypes(unionTypes, config):
|
||||
SortedDictValues(traverseMethods), SortedDictValues(unlinkMethods),
|
||||
SortedDictValues(unionStructs))
|
||||
|
||||
|
||||
def UnionConversions(unionTypes, config):
|
||||
"""
|
||||
The unionTypes argument should be a list of tuples, each containing two
|
||||
@ -1339,6 +1347,7 @@ def UnionConversions(unionTypes, config):
|
||||
if name not in unionConversions:
|
||||
providers = getRelevantProviders(descriptor, config)
|
||||
unionConversions[name] = CGUnionConversionStruct(t, providers[0])
|
||||
|
||||
def addHeadersForType(f, providers):
|
||||
f = f.unroll()
|
||||
if f.isInterface():
|
||||
@ -2028,8 +2037,8 @@ class PropertyDefiner:
|
||||
# pref control is added to members while still allowing us to define all
|
||||
# the members in the smallest number of JSAPI calls.
|
||||
assert len(array) != 0
|
||||
lastCondition = getCondition(array[0], self.descriptor) # So we won't put a specTerminator
|
||||
# at the very front of the list.
|
||||
# So we won't put a specTerminator at the very front of the list:
|
||||
lastCondition = getCondition(array[0], self.descriptor)
|
||||
specs = []
|
||||
prefableSpecs = []
|
||||
|
||||
@ -2107,6 +2116,7 @@ def isMaybeExposedIn(member, descriptor):
|
||||
# and member is not exposed in any worker, then it's not exposed.
|
||||
return not descriptor.workers or member.isExposedInAnyWorker()
|
||||
|
||||
|
||||
def clearableCachedAttrs(descriptor):
|
||||
return (m for m in descriptor.interface.members if
|
||||
m.isAttr() and
|
||||
@ -2114,12 +2124,15 @@ def clearableCachedAttrs(descriptor):
|
||||
m.dependsOn != "Nothing" and
|
||||
m.slotIndex is not None)
|
||||
|
||||
|
||||
def MakeClearCachedValueNativeName(member):
|
||||
return "ClearCached%sValue" % MakeNativeName(member.identifier.name)
|
||||
|
||||
|
||||
def MakeJSImplClearCachedValueNativeName(member):
|
||||
return "_" + MakeClearCachedValueNativeName(member)
|
||||
|
||||
|
||||
def IDLToCIdentifier(name):
|
||||
return name.replace("-", "_")
|
||||
|
||||
@ -2292,8 +2305,8 @@ class MethodDefiner(PropertyDefiner):
|
||||
"nativeName": "UnforgeableValueOf",
|
||||
"methodInfo": False,
|
||||
"length": 0,
|
||||
"flags": "JSPROP_ENUMERATE", # readonly/permanent added
|
||||
# automatically.
|
||||
"flags": "JSPROP_ENUMERATE", # readonly/permanent added
|
||||
# automatically.
|
||||
"condition": MemberCondition(None, None)
|
||||
})
|
||||
|
||||
@ -2405,7 +2418,7 @@ def IsCrossOriginWritable(attr, descriptor):
|
||||
crossOriginWritable = attr.getExtendedAttribute("CrossOriginWritable")
|
||||
if not crossOriginWritable:
|
||||
return False
|
||||
if crossOriginWritable == True:
|
||||
if crossOriginWritable is True:
|
||||
return True
|
||||
assert (isinstance(crossOriginWritable, list) and
|
||||
len(crossOriginWritable) == 1)
|
||||
@ -2585,7 +2598,7 @@ class CGNativeProperties(CGList):
|
||||
if item.get("hasIteratorAlias"):
|
||||
iteratorAliasIndex = index
|
||||
break
|
||||
nativeProps.append(CGGeneric(str(iteratorAliasIndex)));
|
||||
nativeProps.append(CGGeneric(str(iteratorAliasIndex)))
|
||||
return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
|
||||
pre="static const NativeProperties %s = {\n" % name,
|
||||
post="\n};\n")
|
||||
@ -2606,6 +2619,7 @@ class CGNativeProperties(CGList):
|
||||
def define(self):
|
||||
return CGList.define(self)
|
||||
|
||||
|
||||
class CGJsonifyAttributesMethod(CGAbstractMethod):
|
||||
"""
|
||||
Generate the JsonifyAttributes method for an interface descriptor
|
||||
@ -2638,6 +2652,7 @@ class CGJsonifyAttributesMethod(CGAbstractMethod):
|
||||
ret += 'return true;\n'
|
||||
return ret
|
||||
|
||||
|
||||
class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
"""
|
||||
Generate the CreateInterfaceObjects method for an interface descriptor.
|
||||
@ -2891,18 +2906,20 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
# XXX If we ever create non-enumerate properties that can be
|
||||
# aliased, we should consider making the aliases match
|
||||
# the enumerability of the property being aliased.
|
||||
CGGeneric(fill("""
|
||||
if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, JSPROP_ENUMERATE)) {
|
||||
return;
|
||||
}
|
||||
""",
|
||||
defineFn=defineFn,
|
||||
prop=prop))
|
||||
CGGeneric(fill(
|
||||
"""
|
||||
if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, JSPROP_ENUMERATE)) {
|
||||
return;
|
||||
}
|
||||
""",
|
||||
defineFn=defineFn,
|
||||
prop=prop))
|
||||
], "\n")
|
||||
|
||||
def defineAliasesFor(m):
|
||||
return CGList([
|
||||
CGGeneric(fill("""
|
||||
CGGeneric(fill(
|
||||
"""
|
||||
if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) {
|
||||
return;
|
||||
}
|
||||
@ -2991,12 +3008,14 @@ class CGGetProtoObjectMethod(CGAbstractMethod):
|
||||
"""
|
||||
def __init__(self, descriptor):
|
||||
CGAbstractMethod.__init__(
|
||||
self, descriptor, "GetProtoObject", "JSObject*", [Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aGlobal')])
|
||||
self, descriptor, "GetProtoObject", "JSObject*",
|
||||
[Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aGlobal')])
|
||||
|
||||
def definition_body(self):
|
||||
return "return GetProtoObjectHandle(aCx, aGlobal);\n"
|
||||
|
||||
|
||||
class CGGetConstructorObjectHandleMethod(CGGetPerInterfaceObject):
|
||||
"""
|
||||
A method for getting the interface constructor object.
|
||||
@ -3014,18 +3033,21 @@ class CGGetConstructorObjectHandleMethod(CGGetPerInterfaceObject):
|
||||
|
||||
""") + CGGetPerInterfaceObject.definition_body(self)
|
||||
|
||||
|
||||
class CGGetConstructorObjectMethod(CGAbstractMethod):
|
||||
"""
|
||||
A method for getting the interface constructor object.
|
||||
"""
|
||||
def __init__(self, descriptor):
|
||||
CGAbstractMethod.__init__(
|
||||
self, descriptor, "GetConstructorObject", "JSObject*", [Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aGlobal')])
|
||||
self, descriptor, "GetConstructorObject", "JSObject*",
|
||||
[Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aGlobal')])
|
||||
|
||||
def definition_body(self):
|
||||
return "return GetConstructorObjectHandle(aCx, aGlobal);\n"
|
||||
|
||||
|
||||
class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('JSContext*', 'aCx'),
|
||||
@ -3190,11 +3212,13 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
|
||||
conditionsWrapper = ""
|
||||
if len(conditions):
|
||||
conditionsWrapper = CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
|
||||
" &&\n"),
|
||||
pre="return ", post=";\n", reindent=True)
|
||||
conditionsWrapper = CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
|
||||
" &&\n"),
|
||||
pre="return ",
|
||||
post=";\n",
|
||||
reindent=True)
|
||||
else:
|
||||
conditionsWrapper = CGGeneric("return true;\n")
|
||||
conditionsWrapper = CGGeneric("return true;\n")
|
||||
|
||||
body.append(conditionsWrapper)
|
||||
return body.define()
|
||||
@ -3288,6 +3312,7 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode):
|
||||
|
||||
return CGWrapper(CGList(unforgeables), pre="\n")
|
||||
|
||||
|
||||
def CopyUnforgeablePropertiesToInstance(descriptor, wrapperCache):
|
||||
"""
|
||||
Copy the unforgeable properties from the unforgeable holder for
|
||||
@ -4280,7 +4305,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
failureBody=onFailureNotAnObject(failureCode).define())
|
||||
|
||||
if isinstance(defaultValue, IDLNullValue):
|
||||
assert type.nullable() # Parser should enforce this
|
||||
assert type.nullable() # Parser should enforce this
|
||||
templateBody = handleDefault(templateBody, codeToSetNull)
|
||||
elif isinstance(defaultValue, IDLEmptySequenceValue):
|
||||
# Our caller will handle it
|
||||
@ -4311,14 +4336,15 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# For JS-implemented APIs, we refuse to allow passing objects that the
|
||||
# API consumer does not subsume.
|
||||
if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
|
||||
templateBody = fill("""
|
||||
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
|
||||
$*{exceptionCode}
|
||||
}
|
||||
""",
|
||||
sourceDescription=sourceDescription,
|
||||
exceptionCode=exceptionCode) + templateBody
|
||||
templateBody = fill(
|
||||
"""
|
||||
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
|
||||
$*{exceptionCode}
|
||||
}
|
||||
""",
|
||||
sourceDescription=sourceDescription,
|
||||
exceptionCode=exceptionCode) + templateBody
|
||||
|
||||
setToNullCode = "${declName} = nullptr;\n"
|
||||
template = wrapObjectTemplate(templateBody, type, setToNullCode,
|
||||
@ -4395,14 +4421,14 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
arrayRef = "${declName}"
|
||||
|
||||
elementConversion = string.Template(elementInfo.template).substitute({
|
||||
"val": "temp" + str(nestingLevel),
|
||||
"declName": "slot" + str(nestingLevel),
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder" + str(nestingLevel),
|
||||
"passedToJSImpl": "${passedToJSImpl}"
|
||||
})
|
||||
"val": "temp" + str(nestingLevel),
|
||||
"declName": "slot" + str(nestingLevel),
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder" + str(nestingLevel),
|
||||
"passedToJSImpl": "${passedToJSImpl}"
|
||||
})
|
||||
|
||||
# NOTE: Keep this in sync with variadic conversions as needed
|
||||
templateBody = fill(
|
||||
@ -4471,7 +4497,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
assert not isEnforceRange and not isClamp
|
||||
if failureCode is None:
|
||||
notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
|
||||
"%s" % (firstCap(sourceDescription), exceptionCode))
|
||||
"%s" % (firstCap(sourceDescription), exceptionCode))
|
||||
else:
|
||||
notMozMap = failureCode
|
||||
|
||||
@ -4502,14 +4528,14 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
mozMapRef = "${declName}"
|
||||
|
||||
valueConversion = string.Template(valueInfo.template).substitute({
|
||||
"val": "temp",
|
||||
"declName": "slot",
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder",
|
||||
"passedToJSImpl": "${passedToJSImpl}"
|
||||
})
|
||||
"val": "temp",
|
||||
"declName": "slot",
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder",
|
||||
"passedToJSImpl": "${passedToJSImpl}"
|
||||
})
|
||||
|
||||
templateBody = fill(
|
||||
"""
|
||||
@ -5075,7 +5101,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
|
||||
if type.isSpiderMonkeyInterface():
|
||||
assert not isEnforceRange and not isClamp
|
||||
name = type.unroll().name # unroll() because it may be nullable
|
||||
name = type.unroll().name # unroll() because it may be nullable
|
||||
arrayType = CGGeneric(name)
|
||||
declType = arrayType
|
||||
if type.nullable():
|
||||
@ -5347,14 +5373,15 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# For JS-implemented APIs, we refuse to allow passing objects that the
|
||||
# API consumer does not subsume.
|
||||
if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
|
||||
templateBody = fill("""
|
||||
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
|
||||
$*{exceptionCode}
|
||||
}
|
||||
""",
|
||||
sourceDescription=sourceDescription,
|
||||
exceptionCode=exceptionCode) + templateBody
|
||||
templateBody = fill(
|
||||
"""
|
||||
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
|
||||
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
|
||||
$*{exceptionCode}
|
||||
}
|
||||
""",
|
||||
sourceDescription=sourceDescription,
|
||||
exceptionCode=exceptionCode) + templateBody
|
||||
|
||||
# We may not have a default value if we're being converted for
|
||||
# a setter, say.
|
||||
@ -5939,7 +5966,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
$*{recTemplate}
|
||||
""",
|
||||
result=result,
|
||||
setNull=setNull(),
|
||||
setNull=setNull(),
|
||||
recTemplate=recTemplate)
|
||||
return code, recInfall
|
||||
|
||||
@ -6078,7 +6105,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
if not descriptor.hasXPConnectImpls:
|
||||
# Can only fail to wrap as a new-binding object
|
||||
# if they already threw an exception.
|
||||
#XXX Assertion disabled for now, see bug 991271.
|
||||
# XXX Assertion disabled for now, see bug 991271.
|
||||
failed = ("MOZ_ASSERT(true || JS_IsExceptionPending(cx));\n" +
|
||||
exceptionCode)
|
||||
else:
|
||||
@ -6648,6 +6675,7 @@ class MethodNotNewObjectError(Exception):
|
||||
sequenceWrapLevel = 0
|
||||
mapWrapLevel = 0
|
||||
|
||||
|
||||
def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
|
||||
"""
|
||||
Take the thing named by "value" and if it contains "any",
|
||||
@ -7496,7 +7524,7 @@ class CGMethodCall(CGThing):
|
||||
if (distinguishingType(s).isArray() or
|
||||
distinguishingType(s).isDictionary() or
|
||||
distinguishingType(s).isMozMap() or
|
||||
distinguishingType(s).isCallbackInterface()) ]
|
||||
distinguishingType(s).isCallbackInterface())]
|
||||
assert len(genericObjectSigs) <= 1
|
||||
objectSigs.extend(genericObjectSigs)
|
||||
|
||||
@ -7611,6 +7639,7 @@ class FakeIdentifier():
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
class FakeArgument():
|
||||
"""
|
||||
A class that quacks like an IDLArgument. This is used to make
|
||||
@ -7808,6 +7837,7 @@ class CGGenericMethod(CGAbstractBindingMethod):
|
||||
return ok;
|
||||
"""))
|
||||
|
||||
|
||||
class CGGenericPromiseReturningMethod(CGAbstractBindingMethod):
|
||||
"""
|
||||
A class for generating the C++ code for an IDL method that returns a Promise.
|
||||
@ -7819,7 +7849,7 @@ class CGGenericPromiseReturningMethod(CGAbstractBindingMethod):
|
||||
ThrowInvalidThis(cx, args, GetInvalidThisErrorForMethod(%%(securityError)s), "%s");\n
|
||||
return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
|
||||
args.rval());\n""" %
|
||||
descriptor.interface.identifier.name)
|
||||
descriptor.interface.identifier.name)
|
||||
|
||||
name = "genericPromiseReturningMethod"
|
||||
customCallArgs = dedent("""
|
||||
@ -7852,7 +7882,6 @@ class CGGenericPromiseReturningMethod(CGAbstractBindingMethod):
|
||||
"""))
|
||||
|
||||
|
||||
|
||||
class CGSpecializedMethod(CGAbstractStaticMethod):
|
||||
"""
|
||||
A class for generating the C++ code for a specialized method that the JIT
|
||||
@ -7924,7 +7953,7 @@ class CGJsonifierMethod(CGSpecializedMethod):
|
||||
}
|
||||
""")
|
||||
|
||||
jsonDescriptors = [ self.descriptor ]
|
||||
jsonDescriptors = [self.descriptor]
|
||||
interface = self.descriptor.interface.parent
|
||||
while interface:
|
||||
descriptor = self.descriptor.getDescriptor(interface.identifier.name)
|
||||
@ -8446,7 +8475,7 @@ class CGMemberJITInfo(CGThing):
|
||||
assert(not movable or aliasSet != "AliasEverything") # Can't move write-aliasing things
|
||||
assert(not alwaysInSlot or movable) # Things always in slots had better be movable
|
||||
assert(not eliminatable or aliasSet != "AliasEverything") # Can't eliminate write-aliasing things
|
||||
assert(not alwaysInSlot or eliminatable) # Things always in slots had better be eliminatable
|
||||
assert(not alwaysInSlot or eliminatable) # Things always in slots had better be eliminatable
|
||||
|
||||
def jitInfoInitializer(isTypedMethod):
|
||||
initializer = fill(
|
||||
@ -9495,6 +9524,7 @@ class CGUnionConversionStruct(CGThing):
|
||||
|
||||
def define(self):
|
||||
return ""
|
||||
|
||||
def deps(self):
|
||||
return set()
|
||||
|
||||
@ -10567,7 +10597,8 @@ class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
|
||||
callNamedGetter = !hasOnProto;
|
||||
""")
|
||||
if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
computeCondition = fill("""
|
||||
computeCondition = fill(
|
||||
"""
|
||||
if (!isXray) {
|
||||
callNamedGetter = true;
|
||||
} else {
|
||||
@ -10580,6 +10611,8 @@ class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
|
||||
if self.descriptor.supportsIndexedProperties():
|
||||
outerCondition = "!IsArrayIndex(index) && " + outerCondition
|
||||
|
||||
namedGetCode = CGProxyNamedGetter(self.descriptor,
|
||||
templateValues).define()
|
||||
namedGet = fill("""
|
||||
bool callNamedGetter = false;
|
||||
if (${outerCondition}) {
|
||||
@ -10589,9 +10622,9 @@ class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
|
||||
$*{namedGetCode}
|
||||
}
|
||||
""",
|
||||
outerCondition=outerCondition,
|
||||
computeCondition=computeCondition,
|
||||
namedGetCode=CGProxyNamedGetter(self.descriptor, templateValues).define())
|
||||
outerCondition=outerCondition,
|
||||
computeCondition=computeCondition,
|
||||
namedGetCode=namedGetCode)
|
||||
namedGet += "\n"
|
||||
else:
|
||||
namedGet = ""
|
||||
@ -10815,7 +10848,8 @@ class CGDOMJSProxyHandler_delete(ClassMethod):
|
||||
""",
|
||||
namedBody=namedBody)
|
||||
if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
delete = fill("""
|
||||
delete = fill(
|
||||
"""
|
||||
bool hasOnProto;
|
||||
if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
|
||||
return false;
|
||||
@ -10936,7 +10970,8 @@ class CGDOMJSProxyHandler_hasOwn(ClassMethod):
|
||||
""",
|
||||
presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
|
||||
if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
|
||||
named = fill("""
|
||||
named = fill(
|
||||
"""
|
||||
bool hasOnProto;
|
||||
if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
|
||||
return false;
|
||||
@ -11251,8 +11286,9 @@ class CGDOMJSProxyHandler_call(ClassMethod):
|
||||
|
||||
class CGDOMJSProxyHandler_isCallable(ClassMethod):
|
||||
def __init__(self):
|
||||
ClassMethod.__init__(self, "isCallable", "bool", [Argument('JSObject*', 'obj')],
|
||||
virtual=True, override=True, const=True)
|
||||
ClassMethod.__init__(self, "isCallable", "bool",
|
||||
[Argument('JSObject*', 'obj')],
|
||||
virtual=True, override=True, const=True)
|
||||
|
||||
def getBody(self):
|
||||
return dedent("""
|
||||
@ -11284,7 +11320,6 @@ class CGDOMJSProxyHandler(CGClass):
|
||||
explicit=True)
|
||||
]
|
||||
|
||||
|
||||
if descriptor.supportsIndexedProperties():
|
||||
methods.append(CGDOMJSProxyHandler_getElements(descriptor))
|
||||
if (descriptor.operations['IndexedSetter'] is not None or
|
||||
@ -11335,6 +11370,7 @@ def stripTrailingWhitespace(text):
|
||||
lines = text.splitlines()
|
||||
return '\n'.join(line.rstrip() for line in lines) + tail
|
||||
|
||||
|
||||
class MemberProperties:
|
||||
def __init__(self):
|
||||
self.isGenericMethod = False
|
||||
@ -11348,6 +11384,7 @@ class MemberProperties:
|
||||
self.isCrossOriginSetter = False
|
||||
self.isJsonifier = False
|
||||
|
||||
|
||||
def memberProperties(m, descriptor):
|
||||
props = MemberProperties()
|
||||
if m.isMethod():
|
||||
@ -11390,6 +11427,7 @@ def memberProperties(m, descriptor):
|
||||
|
||||
return props
|
||||
|
||||
|
||||
class CGDescriptor(CGThing):
|
||||
def __init__(self, descriptor):
|
||||
CGThing.__init__(self)
|
||||
@ -11735,6 +11773,7 @@ class CGNamespacedEnum(CGThing):
|
||||
def define(self):
|
||||
return ""
|
||||
|
||||
|
||||
def initIdsClassMethod(identifiers, atomCacheName):
|
||||
idinit = ['!atomsCache->%s.init(cx, "%s")' %
|
||||
(CGDictionary.makeIdName(id),
|
||||
@ -11758,6 +11797,7 @@ def initIdsClassMethod(identifiers, atomCacheName):
|
||||
Argument("%s*" % atomCacheName, "atomsCache")
|
||||
], static=True, body=body, visibility="private")
|
||||
|
||||
|
||||
class CGDictionary(CGThing):
|
||||
def __init__(self, dictionary, descriptorProvider):
|
||||
self.dictionary = dictionary
|
||||
@ -12173,7 +12213,7 @@ class CGDictionary(CGThing):
|
||||
"%s");
|
||||
}
|
||||
""" % self.getMemberSourceDescription(member))
|
||||
conversionReplacements["convert"] = indent(conversionReplacements["convert"]).rstrip();
|
||||
conversionReplacements["convert"] = indent(conversionReplacements["convert"]).rstrip()
|
||||
else:
|
||||
conversion += (
|
||||
"if (!isNull && !temp->isUndefined()) {\n"
|
||||
@ -12322,7 +12362,7 @@ class CGDictionary(CGThing):
|
||||
# dictionaries. Either we're being constructed-but-not-initialized
|
||||
# ourselves (and then we don't want to init them) or we're about to
|
||||
# init ourselves and then we'll init them anyway.
|
||||
return CGDictionary.getNonInitializingCtorArg();
|
||||
return CGDictionary.getNonInitializingCtorArg()
|
||||
return None
|
||||
|
||||
def getMemberSourceDescription(self, member):
|
||||
@ -12812,8 +12852,8 @@ class CGBindingRoot(CGThing):
|
||||
|
||||
bindingHeaders["WrapperFactory.h"] = descriptors
|
||||
bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
|
||||
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
|
||||
bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::UnprivilegedJunkScope
|
||||
bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI
|
||||
bindingHeaders["xpcpublic.h"] = dictionaries # xpc::UnprivilegedJunkScope
|
||||
|
||||
cgthings.extend(traverseMethods)
|
||||
cgthings.extend(unlinkMethods)
|
||||
@ -13516,7 +13556,7 @@ class CGBindingImplClass(CGClass):
|
||||
[FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring],
|
||||
FakeMember(),
|
||||
name="aName")]),
|
||||
{ "infallible": True }))
|
||||
{"infallible": True}))
|
||||
|
||||
wrapArgs = [Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aGivenProto')]
|
||||
@ -13571,7 +13611,7 @@ class CGExampleClass(CGBindingImplClass):
|
||||
self.parentIface.identifier.name)
|
||||
bases = [ClassBase(self.nativeLeafName(self.parentDesc))]
|
||||
else:
|
||||
bases = [ ClassBase("nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */") ]
|
||||
bases = [ClassBase("nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */")]
|
||||
if descriptor.wrapperCache:
|
||||
bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
|
||||
|
||||
@ -13622,7 +13662,11 @@ class CGExampleClass(CGBindingImplClass):
|
||||
ccImpl = dedent("""
|
||||
|
||||
// Only needed for refcounted objects.
|
||||
#error "If you don't have members that need cycle collection, then remove all the cycle collection bits from this implementation and the corresponding header. If you do, you want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType}, ${parentType}, your, members, here)"
|
||||
# error "If you don't have members that need cycle collection,
|
||||
# then remove all the cycle collection bits from this
|
||||
# implementation and the corresponding header. If you do, you
|
||||
# want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType},
|
||||
# ${parentType}, your, members, here)"
|
||||
NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
|
||||
NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
|
||||
@ -15072,9 +15116,9 @@ class CGMaplikeOrSetlikeMethodGenerator(CGThing):
|
||||
assert self.maplikeOrSetlike.isMaplike()
|
||||
r = self.appendKeyArgConversion()
|
||||
code = [CGGeneric(dedent(
|
||||
"""
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
"""))]
|
||||
"""
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
"""))]
|
||||
arguments = ["&result"]
|
||||
return self.mergeTuples(r, (code, arguments, []))
|
||||
|
||||
@ -15227,7 +15271,6 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember):
|
||||
return " false"
|
||||
return ""
|
||||
|
||||
|
||||
def getCall(self):
|
||||
return CGMaplikeOrSetlikeMethodGenerator(self.descriptorProvider,
|
||||
self.maplikeOrSetlike,
|
||||
@ -15304,6 +15347,7 @@ class GlobalGenRoots():
|
||||
binaryMemberName = binaryNameFor(m.identifier.name)
|
||||
return ClassMember(CGDictionary.makeIdName(binaryMemberName),
|
||||
"PinnedStringId", visibility="public")
|
||||
|
||||
def buildAtomCacheStructure(idlobj, binaryNameFor, members):
|
||||
classMembers = [memberToAtomCacheMember(binaryNameFor, m)
|
||||
for m in members]
|
||||
@ -15365,7 +15409,7 @@ class GlobalGenRoots():
|
||||
|
||||
@staticmethod
|
||||
def GeneratedEventList(config):
|
||||
eventList = CGList([]);
|
||||
eventList = CGList([])
|
||||
for generatedEvent in config.generatedEvents:
|
||||
eventList.append(CGGeneric(declare=("GENERATED_EVENT(%s)\n" % generatedEvent)))
|
||||
return eventList
|
||||
@ -15524,9 +15568,9 @@ class GlobalGenRoots():
|
||||
register=True,
|
||||
isExposedInSystemGlobals=True,
|
||||
skipGen=False)]
|
||||
defineIncludes.append("nsThreadUtils.h") # For NS_IsMainThread
|
||||
defineIncludes.append("js/Id.h") # For jsid
|
||||
defineIncludes.append("mozilla/dom/BindingUtils.h") # AtomizeAndPinJSString
|
||||
defineIncludes.append("nsThreadUtils.h") # For NS_IsMainThread
|
||||
defineIncludes.append("js/Id.h") # For jsid
|
||||
defineIncludes.append("mozilla/dom/BindingUtils.h") # AtomizeAndPinJSString
|
||||
|
||||
curr = CGHeaders([], [], [], [], [], defineIncludes,
|
||||
'ResolveSystemBinding', curr)
|
||||
@ -15608,11 +15652,14 @@ class GlobalGenRoots():
|
||||
things.update(d.featureDetectibleThings)
|
||||
things = CGList((CGGeneric(declare='"%s",' % t) for t in sorted(things)), joiner="\n")
|
||||
things.append(CGGeneric(declare="nullptr"))
|
||||
things = CGWrapper(CGIndenter(things), pre="static const char* const FeatureList[] = {\n",
|
||||
post="\n};\n")
|
||||
things = CGWrapper(CGIndenter(things),
|
||||
pre="static const char* const FeatureList[] = {\n",
|
||||
post="\n};\n")
|
||||
|
||||
helper = CGWrapper(CGIndenter(things), pre="bool IsFeatureDetectible(const nsAString& aFeature) {\n",
|
||||
post=dedent("""
|
||||
helper_pre = "bool IsFeatureDetectible(const nsAString& aFeature) {\n"
|
||||
helper = CGWrapper(CGIndenter(things),
|
||||
pre=helper_pre,
|
||||
post=dedent("""
|
||||
const char* const* feature = FeatureList;
|
||||
while (*feature) {
|
||||
if (aFeature.EqualsASCII(*feature)) {
|
||||
@ -15631,6 +15678,7 @@ class GlobalGenRoots():
|
||||
|
||||
return curr
|
||||
|
||||
|
||||
# Code generator for simple events
|
||||
class CGEventGetter(CGNativeMember):
|
||||
def __init__(self, descriptor, attr):
|
||||
@ -15733,7 +15781,6 @@ class CGEventMethod(CGNativeMember):
|
||||
if not allowed:
|
||||
raise TypeError("Event code generator does not support methods!")
|
||||
|
||||
|
||||
def getArgs(self, returnType, argList):
|
||||
args = [self.getArg(arg) for arg in argList]
|
||||
return args
|
||||
@ -15769,7 +15816,7 @@ class CGEventMethod(CGNativeMember):
|
||||
iface = self.descriptorProvider.interface
|
||||
members = ""
|
||||
while iface.identifier.name != "Event":
|
||||
i = 3 # Skip the boilerplate args: type, bubble,s cancelable.
|
||||
i = 3 # Skip the boilerplate args: type, bubble,s cancelable.
|
||||
for m in iface.members:
|
||||
if m.isAttr():
|
||||
# We need to initialize all the member variables that do
|
||||
@ -15791,10 +15838,10 @@ class CGEventMethod(CGNativeMember):
|
||||
}
|
||||
${members}
|
||||
""",
|
||||
typeArg = self.args[0].name,
|
||||
bubblesArg = self.args[1].name,
|
||||
cancelableArg = self.args[2].name,
|
||||
members = members)
|
||||
typeArg=self.args[0].name,
|
||||
bubblesArg=self.args[1].name,
|
||||
cancelableArg=self.args[2].name,
|
||||
members=members)
|
||||
|
||||
self.args.append(Argument('ErrorResult&', 'aRv'))
|
||||
|
||||
@ -15825,7 +15872,7 @@ class CGEventMethod(CGNativeMember):
|
||||
# use AppendElements, which is actually a template on
|
||||
# the incoming type on nsTArray and does the right thing
|
||||
# for this case.
|
||||
target = name;
|
||||
target = name
|
||||
source = "%s.%s" % (self.args[1].name, name)
|
||||
sequenceCopy = "e->%s.AppendElements(%s);\n"
|
||||
if m.type.nullable():
|
||||
@ -15846,14 +15893,14 @@ class CGEventMethod(CGNativeMember):
|
||||
e->${varname} = ${srcname}.Value().Obj();
|
||||
}
|
||||
""",
|
||||
varname=name,
|
||||
srcname=srcname);
|
||||
varname=name,
|
||||
srcname=srcname)
|
||||
else:
|
||||
members += fill(
|
||||
"""
|
||||
e->${varname}.set(${srcname}.Obj());
|
||||
""",
|
||||
varname=name, srcname=srcname);
|
||||
varname=name, srcname=srcname)
|
||||
else:
|
||||
members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
|
||||
if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
|
||||
@ -16110,20 +16157,24 @@ class CGEventRoot(CGThing):
|
||||
parent = descriptor.interface.parent.identifier.name
|
||||
|
||||
# Throw in our #includes
|
||||
self.root = CGHeaders([descriptor], [], [], [],
|
||||
[
|
||||
config.getDescriptor(parent, False).headerFile,
|
||||
"mozilla/Attributes.h",
|
||||
"mozilla/ErrorResult.h",
|
||||
"mozilla/dom/%sBinding.h" % interfaceName,
|
||||
'mozilla/dom/BindingUtils.h',
|
||||
],
|
||||
[
|
||||
"%s.h" % interfaceName,
|
||||
"js/GCAPI.h",
|
||||
'mozilla/dom/Nullable.h',
|
||||
],
|
||||
"", self.root, config)
|
||||
self.root = CGHeaders(
|
||||
[descriptor],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
config.getDescriptor(parent, False).headerFile,
|
||||
"mozilla/Attributes.h",
|
||||
"mozilla/ErrorResult.h",
|
||||
"mozilla/dom/%sBinding.h" % interfaceName,
|
||||
'mozilla/dom/BindingUtils.h',
|
||||
],
|
||||
[
|
||||
"%s.h" % interfaceName,
|
||||
"js/GCAPI.h",
|
||||
'mozilla/dom/Nullable.h',
|
||||
],
|
||||
"", self.root, config)
|
||||
|
||||
# And now some include guards
|
||||
self.root = CGIncludeGuard(interfaceName, self.root)
|
||||
|
@ -8,6 +8,7 @@ from collections import defaultdict
|
||||
|
||||
autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
|
||||
|
||||
|
||||
class Configuration:
|
||||
"""
|
||||
Represents global configuration state based on IDL parse data and
|
||||
@ -26,8 +27,8 @@ class Configuration:
|
||||
self.descriptors = []
|
||||
self.interfaces = {}
|
||||
self.optimizedOutDescriptorNames = set()
|
||||
self.generatedEvents = generatedEvents;
|
||||
self.maxProtoChainLength = 0;
|
||||
self.generatedEvents = generatedEvents
|
||||
self.maxProtoChainLength = 0
|
||||
for thing in parseData:
|
||||
if isinstance(thing, IDLImplementsStatement):
|
||||
# Our build system doesn't support dep build involving
|
||||
@ -49,7 +50,7 @@ class Configuration:
|
||||
"%s" %
|
||||
(thing.location, thing.implementor.location))
|
||||
|
||||
assert not thing.isType();
|
||||
assert not thing.isType()
|
||||
|
||||
if not thing.isInterface():
|
||||
continue
|
||||
@ -88,7 +89,7 @@ class Configuration:
|
||||
self.descriptors.extend([Descriptor(self, iface, x) for x in entry])
|
||||
|
||||
# Keep the descriptor list sorted for determinism.
|
||||
self.descriptors.sort(lambda x,y: cmp(x.name, y.name))
|
||||
self.descriptors.sort(lambda x, y: cmp(x.name, y.name))
|
||||
|
||||
self.descriptorsByName = {}
|
||||
for d in self.descriptors:
|
||||
@ -110,7 +111,7 @@ class Configuration:
|
||||
mainTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
|
||||
(mainCallbacks, mainDictionaries) = findCallbacksAndDictionaries(mainTypes)
|
||||
|
||||
workerTypes = set();
|
||||
workerTypes = set()
|
||||
for descriptor in ([self.getDescriptor("DummyInterfaceWorkers", workers=True)] +
|
||||
self.getDescriptors(workers=True, isExternal=False, skipGen=False)):
|
||||
workerTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
|
||||
@ -182,6 +183,7 @@ class Configuration:
|
||||
|
||||
def getInterface(self, ifname):
|
||||
return self.interfaces[ifname]
|
||||
|
||||
def getDescriptors(self, **filters):
|
||||
"""Gets the descriptors that match the given filters."""
|
||||
curr = self.descriptors
|
||||
@ -211,7 +213,7 @@ class Configuration:
|
||||
elif key == 'isJSImplemented':
|
||||
getter = lambda x: x.interface.isJSImplemented()
|
||||
elif key == 'isNavigatorProperty':
|
||||
getter = lambda x: x.interface.getNavigatorProperty() != None
|
||||
getter = lambda x: x.interface.getNavigatorProperty() is not None
|
||||
elif key == 'isExposedInAnyWorker':
|
||||
getter = lambda x: x.interface.isExposedInAnyWorker()
|
||||
elif key == 'isExposedInSystemGlobals':
|
||||
@ -226,6 +228,7 @@ class Configuration:
|
||||
for f in tofilter:
|
||||
curr = filter(lambda x: f[0](x) == f[1], curr)
|
||||
return curr
|
||||
|
||||
def getEnums(self, webIDLFile):
|
||||
return filter(lambda e: e.filename() == webIDLFile, self.enums)
|
||||
|
||||
@ -241,10 +244,12 @@ class Configuration:
|
||||
else:
|
||||
items = filter(lambda x: x.getUserData("mainThread", False), items)
|
||||
else:
|
||||
assert(0) # Unknown key
|
||||
assert(0) # Unknown key
|
||||
return items
|
||||
|
||||
def getDictionaries(self, **filters):
|
||||
return self._filterForFileAndWorkers(self.dictionaries, filters)
|
||||
|
||||
def getCallbacks(self, **filters):
|
||||
return self._filterForFileAndWorkers(self.callbacks, filters)
|
||||
|
||||
@ -271,7 +276,8 @@ class Configuration:
|
||||
"and a consequential interface) without an explicit "
|
||||
"Bindings.conf annotation." % interfaceName)
|
||||
|
||||
raise NoSuchDescriptorError("For " + interfaceName + " found no matches");
|
||||
raise NoSuchDescriptorError("For " + interfaceName + " found no matches")
|
||||
|
||||
def getDescriptorProvider(self, workers):
|
||||
"""
|
||||
Gets a descriptor provider that can provide descriptors as needed,
|
||||
@ -279,10 +285,12 @@ class Configuration:
|
||||
"""
|
||||
return DescriptorProvider(self, workers)
|
||||
|
||||
|
||||
class NoSuchDescriptorError(TypeError):
|
||||
def __init__(self, str):
|
||||
TypeError.__init__(self, str)
|
||||
|
||||
|
||||
class DescriptorProvider:
|
||||
"""
|
||||
A way of getting descriptors for interface names
|
||||
@ -299,6 +307,7 @@ class DescriptorProvider:
|
||||
"""
|
||||
return self.config.getDescriptor(interfaceName, self.workers)
|
||||
|
||||
|
||||
def methodReturnsJSObject(method):
|
||||
assert method.isMethod()
|
||||
if method.returnsPromise():
|
||||
@ -415,6 +424,7 @@ class Descriptor(DescriptorProvider):
|
||||
'LegacyCaller': None,
|
||||
'Jsonifier': None
|
||||
}
|
||||
|
||||
# Stringifiers and jsonifiers need to be set up whether an interface is
|
||||
# concrete or not, because they're actually prototype methods and hence
|
||||
# can apply to instances of descendant interfaces. Legacy callers and
|
||||
@ -443,7 +453,7 @@ class Descriptor(DescriptorProvider):
|
||||
if m.isMethod() and m.isLegacycaller():
|
||||
if not m.isIdentifierLess():
|
||||
raise TypeError("We don't support legacycaller with "
|
||||
"identifier.\n%s" % m.location);
|
||||
"identifier.\n%s" % m.location)
|
||||
if len(m.signatures()) != 1:
|
||||
raise TypeError("We don't support overloaded "
|
||||
"legacycaller.\n%s" % m.location)
|
||||
@ -501,7 +511,7 @@ class Descriptor(DescriptorProvider):
|
||||
iface.setUserData('hasProxyDescendant', True)
|
||||
iface = iface.parent
|
||||
|
||||
if desc.get('wantsQI', None) != None:
|
||||
if desc.get('wantsQI', None) is not None:
|
||||
self._wantsQI = desc.get('wantsQI', None)
|
||||
self.wrapperCache = (not self.interface.isCallback() and
|
||||
desc.get('wrapperCache', True))
|
||||
@ -513,7 +523,7 @@ class Descriptor(DescriptorProvider):
|
||||
# self.extendedAttributes is a dict of dicts, keyed on
|
||||
# all/getterOnly/setterOnly and then on member name. Values are an
|
||||
# array of extended attributes.
|
||||
self.extendedAttributes = { 'all': {}, 'getterOnly': {}, 'setterOnly': {} }
|
||||
self.extendedAttributes = {'all': {}, 'getterOnly': {}, 'setterOnly': {}}
|
||||
|
||||
def addExtendedAttribute(attribute, config):
|
||||
def add(key, members, attribute):
|
||||
@ -713,10 +723,9 @@ class Descriptor(DescriptorProvider):
|
||||
|
||||
"""
|
||||
return (self.interface.isExternal() or self.concrete or
|
||||
self.interface.hasInterfacePrototypeObject() or
|
||||
any((m.isAttr() or m.isMethod()) and m.isStatic() for m
|
||||
in self.interface.members) or
|
||||
self.interface.parent)
|
||||
self.interface.hasInterfacePrototypeObject() or
|
||||
any((m.isAttr() or m.isMethod()) and m.isStatic() for m in self.interface.members) or
|
||||
self.interface.parent)
|
||||
|
||||
def hasThreadChecks(self):
|
||||
return ((self.isExposedConditionally() and
|
||||
@ -759,6 +768,7 @@ class Descriptor(DescriptorProvider):
|
||||
return (self.interface.getExtendedAttribute("Global") or
|
||||
self.interface.getExtendedAttribute("PrimaryGlobal"))
|
||||
|
||||
|
||||
# Some utility methods
|
||||
def getTypesFromDescriptor(descriptor):
|
||||
"""
|
||||
@ -779,6 +789,7 @@ def getTypesFromDescriptor(descriptor):
|
||||
types.extend(a.type for a in members if a.isAttr())
|
||||
return types
|
||||
|
||||
|
||||
def getFlatTypes(types):
|
||||
retval = set()
|
||||
for type in types:
|
||||
@ -789,6 +800,7 @@ def getFlatTypes(types):
|
||||
retval.add(type)
|
||||
return retval
|
||||
|
||||
|
||||
def getTypesFromDictionary(dictionary):
|
||||
"""
|
||||
Get all member types for this dictionary
|
||||
@ -800,16 +812,18 @@ def getTypesFromDictionary(dictionary):
|
||||
curDict = curDict.parent
|
||||
return types
|
||||
|
||||
|
||||
def getTypesFromCallback(callback):
|
||||
"""
|
||||
Get the types this callback depends on: its return type and the
|
||||
types of its arguments.
|
||||
"""
|
||||
sig = callback.signatures()[0]
|
||||
types = [sig[0]] # Return type
|
||||
types.extend(arg.type for arg in sig[1]) # Arguments
|
||||
types = [sig[0]] # Return type
|
||||
types.extend(arg.type for arg in sig[1]) # Arguments
|
||||
return types
|
||||
|
||||
|
||||
def findCallbacksAndDictionaries(inputTypes):
|
||||
"""
|
||||
Ensure that all callbacks and dictionaries reachable from types end up in
|
||||
@ -839,6 +853,7 @@ def findCallbacksAndDictionaries(inputTypes):
|
||||
doFindCallbacksAndDictionaries(inputTypes, retCallbacks, retDictionaries)
|
||||
return (retCallbacks, retDictionaries)
|
||||
|
||||
|
||||
def getAllTypes(descriptors, dictionaries, callbacks):
|
||||
"""
|
||||
Generate all the types we're dealing with. For each type, a tuple
|
||||
|
@ -46,12 +46,13 @@ for [name, prop, id, flags, pref] in propList:
|
||||
extendedAttrs.append('BinaryName="%s"' % prop)
|
||||
# Throw in a '_' before the attribute name, because some of these
|
||||
# property names collide with IDL reserved words.
|
||||
props += " [%s] attribute DOMString _%s;\n" % (", ".join(extendedAttrs),
|
||||
name)
|
||||
props += " [%s] attribute DOMString _%s;\n" % (
|
||||
", ".join(extendedAttrs),
|
||||
name)
|
||||
|
||||
idlFile = open(sys.argv[1], "r");
|
||||
idlTemplate = idlFile.read();
|
||||
idlFile.close();
|
||||
idlFile = open(sys.argv[1], "r")
|
||||
idlTemplate = idlFile.read()
|
||||
idlFile.close()
|
||||
|
||||
print ("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n" +
|
||||
string.Template(idlTemplate).substitute({ "props": props }))
|
||||
string.Template(idlTemplate).substitute({"props": props}))
|
||||
|
@ -19,9 +19,9 @@ from mozbuild.base import MachCommandBase
|
||||
@CommandProvider
|
||||
class WebIDLProvider(MachCommandBase):
|
||||
@Command('webidl-example', category='misc',
|
||||
description='Generate example files for a WebIDL interface.')
|
||||
description='Generate example files for a WebIDL interface.')
|
||||
@CommandArgument('interface', nargs='+',
|
||||
help='Interface(s) whose examples to generate.')
|
||||
help='Interface(s) whose examples to generate.')
|
||||
def webidl_example(self, interface):
|
||||
from mozwebidlcodegen import BuildSystemWebIDL
|
||||
|
||||
@ -30,12 +30,12 @@ class WebIDLProvider(MachCommandBase):
|
||||
manager.generate_example_files(i)
|
||||
|
||||
@Command('webidl-parser-test', category='testing',
|
||||
description='Run WebIDL tests (Interface Browser parser).')
|
||||
description='Run WebIDL tests (Interface Browser parser).')
|
||||
@CommandArgument('--verbose', '-v', action='store_true',
|
||||
help='Run tests in verbose mode.')
|
||||
help='Run tests in verbose mode.')
|
||||
def webidl_test(self, verbose=False):
|
||||
sys.path.insert(0, os.path.join(self.topsrcdir, 'other-licenses',
|
||||
'ply'))
|
||||
'ply'))
|
||||
|
||||
# Make sure we drop our cached grammar bits in the objdir, not
|
||||
# wherever we happen to be running from.
|
||||
@ -45,7 +45,7 @@ class WebIDLProvider(MachCommandBase):
|
||||
# objdir. But we're going to try loading it as a python
|
||||
# module, so we need to make sure the objdir is in our search
|
||||
# path.
|
||||
sys.path.insert(0, self.topobjdir);
|
||||
sys.path.insert(0, self.topobjdir)
|
||||
|
||||
from runtests import run_tests
|
||||
return run_tests(None, verbose=verbose)
|
||||
|
@ -148,8 +148,8 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
}
|
||||
|
||||
def __init__(self, config_path, inputs, exported_header_dir,
|
||||
codegen_dir, state_path, cache_dir=None, make_deps_path=None,
|
||||
make_deps_target=None):
|
||||
codegen_dir, state_path, cache_dir=None, make_deps_path=None,
|
||||
make_deps_target=None):
|
||||
"""Create an instance that manages WebIDLs in the build system.
|
||||
|
||||
config_path refers to a WebIDL config file (e.g. Bindings.conf).
|
||||
@ -176,7 +176,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
self._input_paths = set(input_paths)
|
||||
self._exported_stems = set(exported_stems)
|
||||
self._generated_events_stems = set(generated_events_stems)
|
||||
self._generated_events_stems_as_array = generated_events_stems;
|
||||
self._generated_events_stems_as_array = generated_events_stems
|
||||
self._example_interfaces = set(example_interfaces)
|
||||
self._exported_header_dir = exported_header_dir
|
||||
self._codegen_dir = codegen_dir
|
||||
@ -185,10 +185,10 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
self._make_deps_path = make_deps_path
|
||||
self._make_deps_target = make_deps_target
|
||||
|
||||
if (make_deps_path and not make_deps_target) or (not make_deps_path and
|
||||
make_deps_target):
|
||||
if ((make_deps_path and not make_deps_target) or
|
||||
(not make_deps_path and make_deps_target)):
|
||||
raise Exception('Must define both make_deps_path and make_deps_target '
|
||||
'if one is defined.')
|
||||
'if one is defined.')
|
||||
|
||||
self._parser_results = None
|
||||
self._config = None
|
||||
@ -200,7 +200,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
self._state = WebIDLCodegenManagerState(fh=fh)
|
||||
except Exception as e:
|
||||
self.log(logging.WARN, 'webidl_bad_state', {'msg': str(e)},
|
||||
'Bad WebIDL state: {msg}')
|
||||
'Bad WebIDL state: {msg}')
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
@ -313,8 +313,8 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
from Configuration import Configuration
|
||||
|
||||
self.log(logging.INFO, 'webidl_parse',
|
||||
{'count': len(self._input_paths)},
|
||||
'Parsing {count} WebIDL files.')
|
||||
{'count': len(self._input_paths)},
|
||||
'Parsing {count} WebIDL files.')
|
||||
|
||||
hashes = {}
|
||||
parser = WebIDL.Parser(self._cache_dir)
|
||||
@ -372,7 +372,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
|
||||
# Now we move on to the input files.
|
||||
old_hashes = {v['filename']: v['sha1']
|
||||
for v in self._state['webidls'].values()}
|
||||
for v in self._state['webidls'].values()}
|
||||
|
||||
old_filenames = set(old_hashes.keys())
|
||||
new_filenames = self._input_paths
|
||||
@ -465,8 +465,8 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
)
|
||||
|
||||
self.log(logging.INFO, 'webidl_generate_build_for_input',
|
||||
{'filename': filename},
|
||||
'Generating WebIDL files derived from {filename}')
|
||||
{'filename': filename},
|
||||
'Generating WebIDL files derived from {filename}')
|
||||
|
||||
stem, binding_stem, is_event, header_dir, files = self._binding_info(filename)
|
||||
root = CGBindingRoot(self._config, binding_stem, filename)
|
||||
@ -476,7 +476,7 @@ class WebIDLCodegenManager(LoggingMixin):
|
||||
if is_event:
|
||||
generated_event = CGEventRoot(self._config, stem)
|
||||
result = self._maybe_write_codegen(generated_event, files[2],
|
||||
files[3], result)
|
||||
files[3], result)
|
||||
|
||||
return result, root.deps()
|
||||
|
||||
@ -544,7 +544,7 @@ def create_build_system_manager(topsrcdir, topobjdir, dist_dir):
|
||||
files = json.load(fh)
|
||||
|
||||
inputs = (files['webidls'], files['exported_stems'],
|
||||
files['generated_events_stems'], files['example_interfaces'])
|
||||
files['generated_events_stems'], files['example_interfaces'])
|
||||
|
||||
cache_dir = os.path.join(obj_dir, '_cache')
|
||||
try:
|
||||
|
@ -42,7 +42,7 @@ class TestWebIDLCodegenManager(unittest.TestCase):
|
||||
@property
|
||||
def _static_input_paths(self):
|
||||
s = {mozpath.join(OUR_DIR, p) for p in os.listdir(OUR_DIR)
|
||||
if p.endswith('.webidl')}
|
||||
if p.endswith('.webidl')}
|
||||
|
||||
return s
|
||||
|
||||
@ -98,7 +98,7 @@ class TestWebIDLCodegenManager(unittest.TestCase):
|
||||
manager = WebIDLCodegenManager(**args)
|
||||
|
||||
self.assertEqual(manager._state['version'],
|
||||
WebIDLCodegenManagerState.VERSION)
|
||||
WebIDLCodegenManagerState.VERSION)
|
||||
self.assertNotIn('foobar', manager._state)
|
||||
|
||||
def test_generate_build_files(self):
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -137,7 +137,10 @@ BluetoothManager::DisconnectFromOwner()
|
||||
BluetoothAdapter*
|
||||
BluetoothManager::GetDefaultAdapter()
|
||||
{
|
||||
return DefaultAdapterExists() ? mAdapters[mDefaultAdapterIndex] : nullptr;
|
||||
if (!DefaultAdapterExists()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mAdapters[mDefaultAdapterIndex];
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -40,7 +40,11 @@
|
||||
#include <media/stagefright/MediaDefs.h>
|
||||
#include <media/stagefright/MetaData.h>
|
||||
#include <media/stagefright/OMXClient.h>
|
||||
#if ANDROID_VERSION >= 21
|
||||
#include <media/stagefright/MediaCodecSource.h>
|
||||
#else
|
||||
#include <media/stagefright/OMXCodec.h>
|
||||
#endif
|
||||
#include <media/MediaProfiles.h>
|
||||
|
||||
#include <utils/Errors.h>
|
||||
@ -68,10 +72,21 @@ GonkRecorder::GonkRecorder()
|
||||
GonkRecorder::~GonkRecorder() {
|
||||
RE_LOGV("Destructor");
|
||||
stop();
|
||||
|
||||
#if ANDROID_VERSION >= 21
|
||||
if (mLooper != NULL) {
|
||||
mLooper->stop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
status_t GonkRecorder::init() {
|
||||
RE_LOGV("init");
|
||||
#if ANDROID_VERSION >= 21
|
||||
mLooper = new ALooper;
|
||||
mLooper->setName("recorder_looper");
|
||||
mLooper->start();
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -724,6 +739,71 @@ status_t GonkRecorder::start() {
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
sp<MediaSource> GonkRecorder::createAudioSource() {
|
||||
sp<AudioSource> audioSource =
|
||||
new AudioSource(
|
||||
mAudioSource,
|
||||
mSampleRate,
|
||||
mAudioChannels);
|
||||
|
||||
status_t err = audioSource->initCheck();
|
||||
|
||||
if (err != OK) {
|
||||
RE_LOGE("audio source is not initialized");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sp<AMessage> format = new AMessage;
|
||||
switch (mAudioEncoder) {
|
||||
case AUDIO_ENCODER_AMR_NB:
|
||||
case AUDIO_ENCODER_DEFAULT:
|
||||
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
|
||||
break;
|
||||
case AUDIO_ENCODER_AMR_WB:
|
||||
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB);
|
||||
break;
|
||||
case AUDIO_ENCODER_AAC:
|
||||
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
|
||||
format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
|
||||
break;
|
||||
case AUDIO_ENCODER_HE_AAC:
|
||||
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
|
||||
format->setInt32("aac-profile", OMX_AUDIO_AACObjectHE);
|
||||
break;
|
||||
case AUDIO_ENCODER_AAC_ELD:
|
||||
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
|
||||
format->setInt32("aac-profile", OMX_AUDIO_AACObjectELD);
|
||||
break;
|
||||
|
||||
default:
|
||||
RE_LOGE("Unknown audio encoder: %d", mAudioEncoder);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t maxInputSize;
|
||||
CHECK(audioSource->getFormat()->findInt32(
|
||||
kKeyMaxInputSize, &maxInputSize));
|
||||
|
||||
format->setInt32("max-input-size", maxInputSize);
|
||||
format->setInt32("channel-count", mAudioChannels);
|
||||
format->setInt32("sample-rate", mSampleRate);
|
||||
format->setInt32("bitrate", mAudioBitRate);
|
||||
if (mAudioTimeScale > 0) {
|
||||
format->setInt32("time-scale", mAudioTimeScale);
|
||||
}
|
||||
|
||||
sp<MediaSource> audioEncoder =
|
||||
MediaCodecSource::Create(mLooper, format, audioSource);
|
||||
mAudioSourceNode = audioSource;
|
||||
|
||||
if (audioEncoder == NULL) {
|
||||
RE_LOGE("Failed to create audio encoder");
|
||||
}
|
||||
|
||||
return audioEncoder;
|
||||
}
|
||||
#else
|
||||
sp<MediaSource> GonkRecorder::createAudioSource() {
|
||||
sp<AudioSource> audioSource =
|
||||
new AudioSource(
|
||||
@ -792,6 +872,7 @@ sp<MediaSource> GonkRecorder::createAudioSource() {
|
||||
|
||||
return audioEncoder;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
status_t GonkRecorder::startAACRecording() {
|
||||
@ -1213,6 +1294,87 @@ status_t GonkRecorder::setupCameraSource(
|
||||
return OK;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
status_t GonkRecorder::setupVideoEncoder(
|
||||
sp<MediaSource> cameraSource,
|
||||
int32_t videoBitRate,
|
||||
sp<MediaSource> *source) {
|
||||
source->clear();
|
||||
|
||||
sp<AMessage> format = new AMessage();
|
||||
|
||||
switch (mVideoEncoder) {
|
||||
case VIDEO_ENCODER_H263:
|
||||
format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
|
||||
break;
|
||||
|
||||
case VIDEO_ENCODER_MPEG_4_SP:
|
||||
format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
|
||||
break;
|
||||
|
||||
case VIDEO_ENCODER_H264:
|
||||
format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
|
||||
break;
|
||||
|
||||
case VIDEO_ENCODER_VP8:
|
||||
format->setString("mime", MEDIA_MIMETYPE_VIDEO_VP8);
|
||||
break;
|
||||
|
||||
default:
|
||||
CHECK(!"Should not be here, unsupported video encoding.");
|
||||
break;
|
||||
}
|
||||
|
||||
sp<MetaData> meta = cameraSource->getFormat();
|
||||
|
||||
int32_t width, height, stride, sliceHeight, colorFormat;
|
||||
CHECK(meta->findInt32(kKeyWidth, &width));
|
||||
CHECK(meta->findInt32(kKeyHeight, &height));
|
||||
CHECK(meta->findInt32(kKeyStride, &stride));
|
||||
CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
|
||||
CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
|
||||
|
||||
format->setInt32("width", width);
|
||||
format->setInt32("height", height);
|
||||
format->setInt32("stride", stride);
|
||||
format->setInt32("slice-height", sliceHeight);
|
||||
format->setInt32("color-format", colorFormat);
|
||||
|
||||
format->setInt32("bitrate", videoBitRate);
|
||||
format->setInt32("frame-rate", mFrameRate);
|
||||
format->setInt32("i-frame-interval", mIFramesIntervalSec);
|
||||
|
||||
if (mVideoTimeScale > 0) {
|
||||
format->setInt32("time-scale", mVideoTimeScale);
|
||||
}
|
||||
if (mVideoEncoderProfile != -1) {
|
||||
format->setInt32("profile", mVideoEncoderProfile);
|
||||
}
|
||||
if (mVideoEncoderLevel != -1) {
|
||||
format->setInt32("level", mVideoEncoderLevel);
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (mIsMetaDataStoredInVideoBuffers) {
|
||||
flags |= MediaCodecSource::FLAG_USE_METADATA_INPUT;
|
||||
}
|
||||
|
||||
sp<MediaCodecSource> encoder =
|
||||
MediaCodecSource::Create(mLooper, format, cameraSource, flags);
|
||||
if (encoder == NULL) {
|
||||
RE_LOGE("Failed to create video encoder");
|
||||
// When the encoder fails to be created, we need
|
||||
// release the camera source due to the camera's lock
|
||||
// and unlock mechanism.
|
||||
cameraSource->stop();
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
*source = encoder;
|
||||
|
||||
return OK;
|
||||
}
|
||||
#else
|
||||
status_t GonkRecorder::setupVideoEncoder(
|
||||
sp<MediaSource> cameraSource,
|
||||
int32_t videoBitRate,
|
||||
@ -1301,6 +1463,7 @@ status_t GonkRecorder::setupVideoEncoder(
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
status_t GonkRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
|
||||
status_t status = BAD_VALUE;
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include <camera/CameraParameters.h>
|
||||
#include <utils/String8.h>
|
||||
#include <system/audio.h>
|
||||
#if ANDROID_VERSION >= 21
|
||||
#include <media/stagefright/foundation/ALooper.h>
|
||||
#include <media/stagefright/foundation/AMessage.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "GonkCameraHwMgr.h"
|
||||
@ -111,10 +115,10 @@ private:
|
||||
MediaProfiles *mEncoderProfiles;
|
||||
|
||||
bool mStarted;
|
||||
// Needed when GLFrames are encoded.
|
||||
// An <IGraphicBufferProducer> pointer
|
||||
// will be sent to the client side using which the
|
||||
// frame buffers will be queued and dequeued
|
||||
|
||||
#if ANDROID_VERSION >= 21
|
||||
sp<ALooper> mLooper;
|
||||
#endif
|
||||
|
||||
sp<GonkCameraHardware> mCameraHw;
|
||||
|
||||
|
@ -89,7 +89,10 @@ public:
|
||||
PaintRequest* IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mArray.Length();
|
||||
return aFound ? mArray.ElementAt(aIndex) : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mArray.ElementAt(aIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -689,7 +689,10 @@ TextComposition*
|
||||
TextCompositionArray::GetCompositionFor(nsIWidget* aWidget)
|
||||
{
|
||||
index_type i = IndexOf(aWidget);
|
||||
return i != NoIndex ? ElementAt(i) : nullptr;
|
||||
if (i == NoIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
return ElementAt(i);
|
||||
}
|
||||
|
||||
TextComposition*
|
||||
@ -697,7 +700,10 @@ TextCompositionArray::GetCompositionFor(nsPresContext* aPresContext,
|
||||
nsINode* aNode)
|
||||
{
|
||||
index_type i = IndexOf(aPresContext, aNode);
|
||||
return i != NoIndex ? ElementAt(i) : nullptr;
|
||||
if (i == NoIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
return ElementAt(i);
|
||||
}
|
||||
|
||||
TextComposition*
|
||||
|
@ -345,7 +345,7 @@ MP3TrackDemuxer::GetEvictionOffset(TimeUnit aTime) {
|
||||
|
||||
int64_t
|
||||
MP3TrackDemuxer::StreamLength() const {
|
||||
return mSource->GetLength();
|
||||
return mSource.GetLength();
|
||||
}
|
||||
|
||||
TimeUnit
|
||||
@ -525,8 +525,8 @@ MP3TrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize) {
|
||||
|
||||
uint32_t read = 0;
|
||||
MP3DEMUXER_LOGV("MP3TrackDemuxer::Read -> ReadAt(%d)", aSize);
|
||||
const nsresult rv = mSource->ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
|
||||
static_cast<uint32_t>(aSize), &read);
|
||||
const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
|
||||
static_cast<uint32_t>(aSize), &read);
|
||||
NS_ENSURE_SUCCESS(rv, 0);
|
||||
return static_cast<int32_t>(read);
|
||||
}
|
||||
|
@ -377,7 +377,7 @@ private:
|
||||
double AverageFrameLength() const;
|
||||
|
||||
// The (hopefully) MPEG resource.
|
||||
nsRefPtr<MediaResource> mSource;
|
||||
MediaResourceIndex mSource;
|
||||
|
||||
// MPEG frame parser used to detect frames and extract side info.
|
||||
FrameParser mParser;
|
||||
|
@ -532,7 +532,7 @@ nsresult MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor)
|
||||
|
||||
MediaDecoder* cloneDonor = static_cast<MediaDecoder*>(aCloneDonor);
|
||||
nsresult rv = mDecoderStateMachine->Init(
|
||||
cloneDonor ? cloneDonor->mDecoderStateMachine : nullptr);
|
||||
cloneDonor ? cloneDonor->mDecoderStateMachine.get() : nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If some parameters got set before the state machine got created,
|
||||
|
@ -674,7 +674,7 @@ MediaDecoderStateMachine::PushFront(VideoData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnAudioPopped(const MediaData* aSample)
|
||||
MediaDecoderStateMachine::OnAudioPopped(const nsRefPtr<MediaData>& aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
@ -684,7 +684,7 @@ MediaDecoderStateMachine::OnAudioPopped(const MediaData* aSample)
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoPopped(const MediaData* aSample)
|
||||
MediaDecoderStateMachine::OnVideoPopped(const nsRefPtr<MediaData>& aSample)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
@ -399,8 +399,8 @@ protected:
|
||||
void PushFront(AudioData* aSample);
|
||||
void PushFront(VideoData* aSample);
|
||||
|
||||
void OnAudioPopped(const MediaData* aSample);
|
||||
void OnVideoPopped(const MediaData* aSample);
|
||||
void OnAudioPopped(const nsRefPtr<MediaData>& aSample);
|
||||
void OnVideoPopped(const nsRefPtr<MediaData>& aSample);
|
||||
|
||||
void VolumeChanged();
|
||||
void LogicalPlaybackRateChanged();
|
||||
|
@ -2849,8 +2849,8 @@ GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio)
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_STOP_TRACK,
|
||||
this, nullptr, nullptr,
|
||||
aIsAudio ? mAudioSource : nullptr,
|
||||
!aIsAudio ? mVideoSource : nullptr,
|
||||
aIsAudio ? mAudioSource.get() : nullptr,
|
||||
!aIsAudio ? mVideoSource.get() : nullptr,
|
||||
mFinished, mWindowID, nullptr));
|
||||
} else {
|
||||
LOG(("gUM track %d ended, but we don't have type %s",
|
||||
|
@ -74,7 +74,10 @@ MediaTrack*
|
||||
MediaTrackList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mTracks.Length();
|
||||
return aFound ? mTracks[aIndex] : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mTracks[aIndex];
|
||||
}
|
||||
|
||||
MediaTrack*
|
||||
|
@ -814,6 +814,12 @@ public:
|
||||
MozPromiseRequestHolder() {}
|
||||
~MozPromiseRequestHolder() { MOZ_ASSERT(!mRequest); }
|
||||
|
||||
void Begin(nsRefPtr<typename PromiseType::Request>&& aRequest)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Exists());
|
||||
mRequest = Move(aRequest);
|
||||
}
|
||||
|
||||
void Begin(typename PromiseType::Request* aRequest)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Exists());
|
||||
|
@ -50,7 +50,10 @@ TextTrackCue*
|
||||
TextTrackCueList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mList.Length();
|
||||
return aFound ? mList[aIndex] : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mList[aIndex];
|
||||
}
|
||||
|
||||
TextTrackCue*
|
||||
|
@ -69,7 +69,10 @@ TextTrack*
|
||||
TextTrackList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mTextTracks.Length();
|
||||
return aFound ? mTextTracks[aIndex] : nullptr;
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mTextTracks[aIndex];
|
||||
}
|
||||
|
||||
TextTrack*
|
||||
|
@ -38,7 +38,11 @@ SourceBufferList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aFound = aIndex < mSourceBuffers.Length();
|
||||
return aFound ? mSourceBuffers[aIndex] : nullptr;
|
||||
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mSourceBuffers[aIndex];
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -276,7 +276,7 @@ void
|
||||
AppleVDADecoder::DrainReorderedFrames()
|
||||
{
|
||||
while (!mReorderQueue.IsEmpty()) {
|
||||
mCallback->Output(mReorderQueue.Pop());
|
||||
mCallback->Output(mReorderQueue.Pop().get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,7 +406,7 @@ AppleVDADecoder::OutputFrame(CFRefPtr<CVPixelBufferRef> aImage,
|
||||
// in composition order.
|
||||
mReorderQueue.Push(data);
|
||||
while (mReorderQueue.Length() > mMaxRefFrames) {
|
||||
mCallback->Output(mReorderQueue.Pop());
|
||||
mCallback->Output(mReorderQueue.Pop().get());
|
||||
}
|
||||
LOG("%llu decoded frames queued",
|
||||
static_cast<unsigned long long>(mReorderQueue.Length()));
|
||||
|
@ -1709,13 +1709,18 @@ PeerConnectionWrapper.prototype = {
|
||||
rId = stats[name].remoteCandidateId;
|
||||
}
|
||||
});
|
||||
info("checkStatsIceConnectionType verifying: local=" +
|
||||
JSON.stringify(stats[lId]) + " remote=" + JSON.stringify(stats[rId]));
|
||||
ok(typeof lId !== 'undefined', "Got local candidate ID " +
|
||||
JSON.stringify(lId) + " for selected pair");
|
||||
ok(typeof rId !== 'undefined', "Got remote candidate ID " +
|
||||
JSON.stringify(rId) + " for selected pair");
|
||||
if ((typeof stats[lId] === 'undefined') ||
|
||||
(typeof stats[rId] === 'undefined')) {
|
||||
info("checkStatsIceConnectionType failed to find candidatepair IDs");
|
||||
ok(false, "failed to find candidatepair IDs or stats for local: " +
|
||||
JSON.stringify(lId) + " remote: " + JSON.stringify(rId));
|
||||
return;
|
||||
}
|
||||
info("checkStatsIceConnectionType verifying: local=" +
|
||||
JSON.stringify(stats[lId]) + " remote=" + JSON.stringify(stats[rId]));
|
||||
var lType = stats[lId].candidateType;
|
||||
var rType = stats[rId].candidateType;
|
||||
var lIp = stats[lId].ipAddress;
|
||||
@ -1754,6 +1759,7 @@ PeerConnectionWrapper.prototype = {
|
||||
}
|
||||
});
|
||||
info("ICE connections according to stats: " + numIceConnections);
|
||||
isnot(numIceConnections, 0, "Number of ICE connections according to stats is not zero");
|
||||
if (answer.sdp.includes('a=group:BUNDLE')) {
|
||||
is(numIceConnections, 1, "stats reports exactly 1 ICE connection");
|
||||
} else {
|
||||
|
@ -461,25 +461,25 @@ var commandsPeerConnectionOfferAnswer = [
|
||||
},
|
||||
|
||||
function PC_REMOTE_CHECK_STATS(test) {
|
||||
test.pcRemote.getStats().then(stats => {
|
||||
return test.pcRemote.getStats().then(stats => {
|
||||
test.pcRemote.checkStats(stats, test.steeplechase);
|
||||
});
|
||||
},
|
||||
|
||||
function PC_LOCAL_CHECK_ICE_CONNECTION_TYPE(test) {
|
||||
test.pcLocal.getStats().then(stats => {
|
||||
return test.pcLocal.getStats().then(stats => {
|
||||
test.pcLocal.checkStatsIceConnectionType(stats);
|
||||
});
|
||||
},
|
||||
|
||||
function PC_REMOTE_CHECK_ICE_CONNECTION_TYPE(test) {
|
||||
test.pcRemote.getStats().then(stats => {
|
||||
return test.pcRemote.getStats().then(stats => {
|
||||
test.pcRemote.checkStatsIceConnectionType(stats);
|
||||
});
|
||||
},
|
||||
|
||||
function PC_LOCAL_CHECK_ICE_CONNECTIONS(test) {
|
||||
test.pcLocal.getStats().then(stats => {
|
||||
return test.pcLocal.getStats().then(stats => {
|
||||
test.pcLocal.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
@ -488,7 +488,7 @@ var commandsPeerConnectionOfferAnswer = [
|
||||
},
|
||||
|
||||
function PC_REMOTE_CHECK_ICE_CONNECTIONS(test) {
|
||||
test.pcRemote.getStats().then(stats => {
|
||||
return test.pcRemote.getStats().then(stats => {
|
||||
test.pcRemote.checkStatsIceConnections(stats,
|
||||
test._offer_constraints,
|
||||
test._offer_options,
|
||||
|
@ -88,10 +88,10 @@ class WebMPacketQueue {
|
||||
mQueue.push_front(Move(aItem));
|
||||
}
|
||||
|
||||
nsRefPtr<NesteggPacketHolder> PopFront() {
|
||||
already_AddRefed<NesteggPacketHolder> PopFront() {
|
||||
nsRefPtr<NesteggPacketHolder> result = mQueue.front();
|
||||
mQueue.pop_front();
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
|
@ -880,7 +880,8 @@ WebMTrackDemuxer::SetNextKeyFrameTime()
|
||||
skipSamplesQueue.PushFront(sample);
|
||||
}
|
||||
while(skipSamplesQueue.GetSize()) {
|
||||
mSamples.PushFront(skipSamplesQueue.PopFront());
|
||||
nsRefPtr<MediaRawData> data = skipSamplesQueue.PopFront();
|
||||
mSamples.PushFront(data);
|
||||
}
|
||||
if (frameTime == -1) {
|
||||
frameTime = mParent->GetNextKeyframeTime();
|
||||
|
@ -32,10 +32,10 @@ class MediaRawDataQueue {
|
||||
mQueue.push_front(aItem);
|
||||
}
|
||||
|
||||
nsRefPtr<MediaRawData> PopFront() {
|
||||
already_AddRefed<MediaRawData> PopFront() {
|
||||
nsRefPtr<MediaRawData> result = mQueue.front();
|
||||
mQueue.pop_front();
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
|
@ -670,7 +670,8 @@ int64_t WebMReader::GetNextKeyframeTime(int64_t aTimeThreshold)
|
||||
// Restore the packets before we return -1.
|
||||
uint32_t size = skipPacketQueue.GetSize();
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
PushVideoPacket(skipPacketQueue.PopFront());
|
||||
nsRefPtr<NesteggPacketHolder> packetHolder = skipPacketQueue.PopFront();
|
||||
PushVideoPacket(packetHolder);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -694,7 +695,8 @@ int64_t WebMReader::GetNextKeyframeTime(int64_t aTimeThreshold)
|
||||
|
||||
uint32_t size = skipPacketQueue.GetSize();
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
PushVideoPacket(skipPacketQueue.PopFront());
|
||||
nsRefPtr<NesteggPacketHolder> packetHolder = skipPacketQueue.PopFront();
|
||||
PushVideoPacket(packetHolder);
|
||||
}
|
||||
|
||||
return keyframeTime;
|
||||
|
@ -41,7 +41,7 @@ PluginScriptableObjectChild::IdentifierTable PluginScriptableObjectChild::sIdent
|
||||
/* static */ PluginScriptableObjectChild::StoredIdentifier*
|
||||
PluginScriptableObjectChild::HashIdentifier(const nsCString& aIdentifier)
|
||||
{
|
||||
StoredIdentifier* stored = sIdentifiers.Get(aIdentifier);
|
||||
StoredIdentifier* stored = sIdentifiers.Get(aIdentifier).get();
|
||||
if (stored) {
|
||||
return stored;
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ SVGAngle::SetValue(float aValue, ErrorResult& rv)
|
||||
return;
|
||||
}
|
||||
bool isBaseVal = mType == BaseValue;
|
||||
mVal->SetBaseValue(aValue, isBaseVal ? mSVGElement : nullptr, isBaseVal);
|
||||
mVal->SetBaseValue(aValue, isBaseVal ? mSVGElement.get() : nullptr,
|
||||
isBaseVal);
|
||||
}
|
||||
|
||||
float
|
||||
@ -83,7 +84,8 @@ SVGAngle::NewValueSpecifiedUnits(uint16_t unitType,
|
||||
return;
|
||||
}
|
||||
rv = mVal->NewValueSpecifiedUnits(unitType, valueInSpecifiedUnits,
|
||||
mType == BaseValue ? mSVGElement : nullptr);
|
||||
mType == BaseValue ? mSVGElement.get()
|
||||
: nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -93,7 +95,8 @@ SVGAngle::ConvertToSpecifiedUnits(uint16_t unitType, ErrorResult& rv)
|
||||
rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
rv = mVal->ConvertToSpecifiedUnits(unitType, mType == BaseValue ? mSVGElement : nullptr);
|
||||
rv = mVal->ConvertToSpecifiedUnits(unitType, mType == BaseValue ?
|
||||
mSVGElement.get() : nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -104,7 +107,8 @@ SVGAngle::SetValueAsString(const nsAString& aValue, ErrorResult& rv)
|
||||
return;
|
||||
}
|
||||
bool isBaseVal = mType == BaseValue;
|
||||
rv = mVal->SetBaseValueString(aValue, isBaseVal ? mSVGElement : nullptr, isBaseVal);
|
||||
rv = mVal->SetBaseValueString(aValue, isBaseVal ? mSVGElement.get() : nullptr,
|
||||
isBaseVal);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -880,8 +880,8 @@ nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream,
|
||||
mBaseTag = do_GetAtom(baseTag);
|
||||
}
|
||||
|
||||
aDocument->CreateElem(NS_LITERAL_STRING("binding"), nullptr, kNameSpaceID_XBL,
|
||||
getter_AddRefs(mBinding));
|
||||
mBinding = aDocument->CreateElem(NS_LITERAL_STRING("binding"), nullptr,
|
||||
kNameSpaceID_XBL);
|
||||
|
||||
nsCOMPtr<nsIContent> child;
|
||||
rv = ReadContentNode(aStream, aDocument, aDocument->NodeInfoManager(), getter_AddRefs(child));
|
||||
|
@ -125,15 +125,13 @@ createAndAddToResult(nsIAtom* aName, const nsSubstring& aValue,
|
||||
"invalid result-holder");
|
||||
|
||||
nsIDocument* doc = aResultHolder->OwnerDoc();
|
||||
nsCOMPtr<nsIContent> elem;
|
||||
nsresult rv = doc->CreateElem(nsDependentAtomString(aName),
|
||||
nullptr, kNameSpaceID_None,
|
||||
getter_AddRefs(elem));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<Element> elem = doc->CreateElem(nsDependentAtomString(aName),
|
||||
nullptr, kNameSpaceID_None);
|
||||
NS_ENSURE_TRUE(elem, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsRefPtr<nsTextNode> text = new nsTextNode(doc->NodeInfoManager());
|
||||
|
||||
rv = text->SetText(aValue, false);
|
||||
nsresult rv = text->SetText(aValue, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = elem->AppendChildTo(text, false);
|
||||
|
@ -175,10 +175,9 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument,
|
||||
RegisterNameSpace(NS_LITERAL_STRING(kTXNameSpaceURI), namespaceID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
|
||||
nsGkAtoms::transformiix, namespaceID,
|
||||
getter_AddRefs(mTextParent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mTextParent =
|
||||
mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
|
||||
nsGkAtoms::transformiix, namespaceID);
|
||||
|
||||
|
||||
rv = mDocument->AppendChildTo(mTextParent, true);
|
||||
|
@ -619,11 +619,9 @@ txMozillaXMLOutput::createTxWrapper()
|
||||
RegisterNameSpace(NS_LITERAL_STRING(kTXNameSpaceURI), namespaceID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIContent> wrapper;
|
||||
rv = mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
|
||||
nsGkAtoms::transformiix, namespaceID,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<Element> wrapper =
|
||||
mDocument->CreateElem(nsDependentAtomString(nsGkAtoms::result),
|
||||
nsGkAtoms::transformiix, namespaceID);
|
||||
|
||||
uint32_t i, j, childCount = mDocument->GetChildCount();
|
||||
#ifdef DEBUG
|
||||
|
@ -3719,11 +3719,9 @@ XULDocument::CreateTemplateBuilder(nsIContent* aElement)
|
||||
getter_AddRefs(bodyContent));
|
||||
|
||||
if (! bodyContent) {
|
||||
nsresult rv =
|
||||
bodyContent =
|
||||
document->CreateElem(nsDependentAtomString(nsGkAtoms::treechildren),
|
||||
nullptr, kNameSpaceID_XUL,
|
||||
getter_AddRefs(bodyContent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nullptr, kNameSpaceID_XUL);
|
||||
|
||||
aElement->AppendChildTo(bodyContent, false);
|
||||
}
|
||||
|
@ -4652,11 +4652,8 @@ nsEditor::CreateHTMLContent(nsIAtom* aTag)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> ret;
|
||||
nsresult res = doc->CreateElem(nsDependentAtomString(aTag), nullptr,
|
||||
kNameSpaceID_XHTML, getter_AddRefs(ret));
|
||||
NS_ENSURE_SUCCESS(res, nullptr);
|
||||
return dont_AddRef(ret.forget().take()->AsElement());
|
||||
return doc->CreateElem(nsDependentAtomString(aTag), nullptr,
|
||||
kNameSpaceID_XHTML);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -24,6 +24,11 @@
|
||||
#include "GLLibraryEGL.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "MacIOSurfaceImage.h"
|
||||
#include "GLContextCGL.h"
|
||||
#endif
|
||||
|
||||
using mozilla::layers::PlanarYCbCrImage;
|
||||
using mozilla::layers::PlanarYCbCrData;
|
||||
|
||||
@ -155,8 +160,10 @@ GLBlitHelper::GLBlitHelper(GLContext* gl)
|
||||
, mTextureTransformLoc(-1)
|
||||
, mTexExternalBlit_FragShader(0)
|
||||
, mTexYUVPlanarBlit_FragShader(0)
|
||||
, mTexNV12PlanarBlit_FragShader(0)
|
||||
, mTexExternalBlit_Program(0)
|
||||
, mTexYUVPlanarBlit_Program(0)
|
||||
, mTexNV12PlanarBlit_Program(0)
|
||||
, mFBO(0)
|
||||
, mSrcTexY(0)
|
||||
, mSrcTexCb(0)
|
||||
@ -301,6 +308,33 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
} \n\
|
||||
";
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
const char kTexNV12PlanarBlit_FragShaderSource[] = "\
|
||||
#extension GL_ARB_texture_rectangle : require \n\
|
||||
#ifdef GL_ES \n\
|
||||
precision mediump float \n\
|
||||
#endif \n\
|
||||
varying vec2 vTexCoord; \n\
|
||||
uniform sampler2DRect uYTexture; \n\
|
||||
uniform sampler2DRect uCbCrTexture; \n\
|
||||
uniform vec2 uYTexScale; \n\
|
||||
uniform vec2 uCbCrTexScale; \n\
|
||||
void main() \n\
|
||||
{ \n\
|
||||
float y = texture2DRect(uYTexture, vTexCoord * uYTexScale).r; \n\
|
||||
float cb = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).r; \n\
|
||||
float cr = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).a; \n\
|
||||
y = (y - 0.06275) * 1.16438; \n\
|
||||
cb = cb - 0.50196; \n\
|
||||
cr = cr - 0.50196; \n\
|
||||
gl_FragColor.r = y + cr * 1.59603; \n\
|
||||
gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb; \n\
|
||||
gl_FragColor.b = y + cb * 2.01723; \n\
|
||||
gl_FragColor.a = 1.0; \n\
|
||||
} \n\
|
||||
";
|
||||
#endif
|
||||
|
||||
bool success = false;
|
||||
|
||||
GLuint *programPtr;
|
||||
@ -331,6 +365,13 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
|
||||
fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
|
||||
break;
|
||||
#ifdef XP_MACOSX
|
||||
case ConvertMacIOSurfaceImage:
|
||||
programPtr = &mTexNV12PlanarBlit_Program;
|
||||
fragShaderPtr = &mTexNV12PlanarBlit_FragShader;
|
||||
fragShaderSource = kTexNV12PlanarBlit_FragShaderSource;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -483,6 +524,24 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
mGL->fUniform1i(texCr, Channel_Cr);
|
||||
break;
|
||||
}
|
||||
case ConvertMacIOSurfaceImage: {
|
||||
#ifdef XP_MACOSX
|
||||
GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
|
||||
GLint texCbCr = mGL->fGetUniformLocation(program, "uCbCrTexture");
|
||||
mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
|
||||
mCbCrTexScaleLoc= mGL->fGetUniformLocation(program, "uCbCrTexScale");
|
||||
|
||||
DebugOnly<bool> hasUniformLocations = texY != -1 &&
|
||||
texCbCr != -1 &&
|
||||
mYTexScaleLoc != -1 &&
|
||||
mCbCrTexScaleLoc != -1;
|
||||
MOZ_ASSERT(hasUniformLocations, "uniforms not found");
|
||||
|
||||
mGL->fUniform1i(texY, Channel_Y);
|
||||
mGL->fUniform1i(texCbCr, Channel_Cb);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
|
||||
mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
|
||||
@ -565,6 +624,10 @@ GLBlitHelper::DeleteTexBlitProgram()
|
||||
mGL->fDeleteShader(mTexYUVPlanarBlit_FragShader);
|
||||
mTexYUVPlanarBlit_FragShader = 0;
|
||||
}
|
||||
if (mTexNV12PlanarBlit_FragShader) {
|
||||
mGL->fDeleteShader(mTexNV12PlanarBlit_FragShader);
|
||||
mTexNV12PlanarBlit_FragShader = 0;
|
||||
}
|
||||
if (mTexExternalBlit_Program) {
|
||||
mGL->fDeleteProgram(mTexExternalBlit_Program);
|
||||
mTexExternalBlit_Program = 0;
|
||||
@ -573,6 +636,10 @@ GLBlitHelper::DeleteTexBlitProgram()
|
||||
mGL->fDeleteProgram(mTexYUVPlanarBlit_Program);
|
||||
mTexYUVPlanarBlit_Program = 0;
|
||||
}
|
||||
if (mTexNV12PlanarBlit_Program) {
|
||||
mGL->fDeleteProgram(mTexNV12PlanarBlit_Program);
|
||||
mTexNV12PlanarBlit_Program = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -816,6 +883,47 @@ GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
bool
|
||||
GLBlitHelper::BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage)
|
||||
{
|
||||
ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
|
||||
MacIOSurface* surf = ioImage->GetSurface();
|
||||
|
||||
GLint oldTex[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
|
||||
}
|
||||
|
||||
GLuint textures[2];
|
||||
mGL->fGenTextures(2, textures);
|
||||
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[0]);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
surf->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(mGL)->GetCGLContext(), 0);
|
||||
mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
|
||||
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[1]);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
surf->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(mGL)->GetCGLContext(), 1);
|
||||
mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
|
||||
|
||||
mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
|
||||
}
|
||||
|
||||
mGL->fDeleteTextures(2, textures);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
|
||||
const gfx::IntSize& destSize,
|
||||
@ -852,6 +960,12 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
|
||||
srcOrigin = static_cast<layers::EGLImageImage*>(srcImage)->GetData()->mOriginPos;
|
||||
break;
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
case ImageFormat::MAC_IOSURFACE:
|
||||
type = ConvertMacIOSurfaceImage;
|
||||
srcOrigin = OriginPos::TopLeft;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
@ -887,6 +1001,11 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
|
||||
return BlitEGLImageImage(static_cast<layers::EGLImageImage*>(srcImage));
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
case ConvertMacIOSurfaceImage:
|
||||
return BlitMacIOSurfaceImage(static_cast<layers::MacIOSurfaceImage*>(srcImage));
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ class Image;
|
||||
class PlanarYCbCrImage;
|
||||
class GrallocImage;
|
||||
class SurfaceTextureImage;
|
||||
class MacIOSurfaceImage;
|
||||
class EGLImageImage;
|
||||
} // namespace layers
|
||||
|
||||
@ -100,7 +101,8 @@ class GLBlitHelper final
|
||||
ConvertGralloc,
|
||||
ConvertPlanarYCbCr,
|
||||
ConvertSurfaceTexture,
|
||||
ConvertEGLImage
|
||||
ConvertEGLImage,
|
||||
ConvertMacIOSurfaceImage
|
||||
};
|
||||
// The GLContext is the sole owner of the GLBlitHelper.
|
||||
GLContext* mGL;
|
||||
@ -119,8 +121,10 @@ class GLBlitHelper final
|
||||
// Data for image blit path
|
||||
GLuint mTexExternalBlit_FragShader;
|
||||
GLuint mTexYUVPlanarBlit_FragShader;
|
||||
GLuint mTexNV12PlanarBlit_FragShader;
|
||||
GLuint mTexExternalBlit_Program;
|
||||
GLuint mTexYUVPlanarBlit_Program;
|
||||
GLuint mTexNV12PlanarBlit_Program;
|
||||
GLuint mFBO;
|
||||
GLuint mSrcTexY;
|
||||
GLuint mSrcTexCb;
|
||||
@ -153,6 +157,9 @@ class GLBlitHelper final
|
||||
bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage);
|
||||
bool BlitEGLImageImage(layers::EGLImageImage* eglImage);
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
bool BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage);
|
||||
#endif
|
||||
|
||||
explicit GLBlitHelper(GLContext* gl);
|
||||
|
||||
|
@ -131,7 +131,10 @@ TextureHost::SendDeleteIPDLActor(PTextureParent* actor)
|
||||
TextureHost*
|
||||
TextureHost::AsTextureHost(PTextureParent* actor)
|
||||
{
|
||||
return actor? static_cast<TextureParent*>(actor)->mTextureHost : nullptr;
|
||||
if (!actor) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<TextureParent*>(actor)->mTextureHost;
|
||||
}
|
||||
|
||||
PTextureParent*
|
||||
|
@ -2985,7 +2985,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
convertedString,
|
||||
true,
|
||||
mStyle.explicitLanguage
|
||||
? mStyle.language : nullptr,
|
||||
? mStyle.language.get() : nullptr,
|
||||
charsToMergeArray,
|
||||
deletedCharsArray);
|
||||
|
||||
|
@ -226,6 +226,15 @@ function ArrayForEach(callbackfn/*, thisArg*/) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
function ArrayStaticForEach(list, callbackfn/*, thisArg*/) {
|
||||
if (arguments.length < 2)
|
||||
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.forEach');
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
|
||||
var T = arguments.length > 2 ? arguments[2] : void 0;
|
||||
callFunction(ArrayForEach, list, callbackfn, T);
|
||||
}
|
||||
|
||||
/* ES5 15.4.4.19. */
|
||||
function ArrayMap(callbackfn/*, thisArg*/) {
|
||||
/* Step 1. */
|
||||
@ -270,13 +279,52 @@ function ArrayStaticMap(list, callbackfn/*, thisArg*/) {
|
||||
return callFunction(ArrayMap, list, callbackfn, T);
|
||||
}
|
||||
|
||||
function ArrayStaticForEach(list, callbackfn/*, thisArg*/) {
|
||||
/* ES2015 22.1.3.7 Array.prototype.filter. */
|
||||
function ArrayFilter(callbackfn/*, thisArg*/) {
|
||||
/* Steps 1-2. */
|
||||
var O = ToObject(this);
|
||||
|
||||
/* Steps 3-4. */
|
||||
var len = ToInteger(O.length);
|
||||
|
||||
/* Step 5. */
|
||||
if (arguments.length === 0)
|
||||
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.filter');
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
|
||||
|
||||
/* Step 6. */
|
||||
var T = arguments.length > 1 ? arguments[1] : void 0;
|
||||
|
||||
/* Step 7. */
|
||||
var A = [];
|
||||
|
||||
/* Steps 8-11. */
|
||||
/* Steps 11.a (implicit), and 11.e. */
|
||||
for (var k = 0, to = 0; k < len; k++) {
|
||||
/* Steps 11.b-c. */
|
||||
if (k in O) {
|
||||
/* Steps 11.c.i-ii. */
|
||||
var kValue = O[k];
|
||||
/* Steps 11.c.iii-iv. */
|
||||
var selected = callFunction(callbackfn, T, kValue, k, O);
|
||||
/* Step 11.c.v. */
|
||||
if (selected)
|
||||
_DefineDataProperty(A, to++, kValue);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 12. */
|
||||
return A;
|
||||
}
|
||||
|
||||
function ArrayStaticFilter(list, callbackfn/*, thisArg*/) {
|
||||
if (arguments.length < 2)
|
||||
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.forEach');
|
||||
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'Array.filter');
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
|
||||
var T = arguments.length > 2 ? arguments[2] : void 0;
|
||||
callFunction(ArrayForEach, list, callbackfn, T);
|
||||
return callFunction(ArrayFilter, list, callbackfn, T);
|
||||
}
|
||||
|
||||
/* ES5 15.4.4.21. */
|
||||
@ -793,3 +841,111 @@ function ArrayToString() {
|
||||
return callFunction(std_Object_toString, array);
|
||||
return callFunction(func, array);
|
||||
}
|
||||
|
||||
//ES 2015, 22.1.3.25 Array.prototype.splice.
|
||||
function ArraySplice(start, deleteCount /*, ...items */) {
|
||||
// Steps 1-2.
|
||||
var O = ToObject(this);
|
||||
|
||||
// Steps 3-4.
|
||||
// FIXME: Array operations should use ToLength (bug 924058).
|
||||
var len = ToInteger(O.length);
|
||||
|
||||
// Steps 5-6.
|
||||
var relativeStart = ToInteger(start);
|
||||
|
||||
// Step 7.
|
||||
var actualStart = relativeStart < 0
|
||||
? std_Math_max(len + relativeStart, 0)
|
||||
: std_Math_min(relativeStart, len);
|
||||
|
||||
// Steps 8-10.
|
||||
var insertCount = 0;
|
||||
var actualDeleteCount = 0;
|
||||
var numArgs = arguments.length;
|
||||
if (numArgs === 1) {
|
||||
actualDeleteCount = len - actualStart;
|
||||
} else if (numArgs > 1) {
|
||||
// Step 10.a.
|
||||
insertCount = numArgs - 2;
|
||||
// Steps 10.b-c.
|
||||
var dc = ToInteger(deleteCount);
|
||||
// Step 10.d.
|
||||
actualDeleteCount = std_Math_min(std_Math_max(dc, 0), len - actualStart);
|
||||
}
|
||||
|
||||
// Step 11.
|
||||
if (len + insertCount - actualDeleteCount > 2 ** 53 - 1)
|
||||
ThrowTypeError(JSMSG_BAD_ARRAY_LENGTH_SPLICE);
|
||||
|
||||
// Steps 12-13.
|
||||
// FIXME: Use ArraySpeciesCreate here.
|
||||
var A = NewDenseArray(actualDeleteCount);
|
||||
|
||||
// Steps 14-15.
|
||||
for (var k = 0; k < actualDeleteCount; k++) {
|
||||
// Step 15.a.
|
||||
var from = actualStart + k;
|
||||
// Steps 15.b-d.
|
||||
if (from in O)
|
||||
_DefineDataProperty(A, k, O[from]);
|
||||
}
|
||||
|
||||
// Steps 16-17.
|
||||
A.length = actualDeleteCount;
|
||||
|
||||
// Step 18 (implicit).
|
||||
// Step 19.
|
||||
var itemCount = insertCount;
|
||||
|
||||
// Step 20.
|
||||
if (itemCount < actualDeleteCount) {
|
||||
// Steps 20.a-b.
|
||||
for (var k = actualStart, kMax = len - actualDeleteCount; k < kMax; k++) {
|
||||
// Step 20.b.i.
|
||||
var from = k + actualDeleteCount;
|
||||
// Step 20.b.ii.
|
||||
var to = k + itemCount;
|
||||
// Steps 20.b.iii-v.
|
||||
if (from in O) {
|
||||
O[to] = O[from];
|
||||
} else {
|
||||
// Step 20.b.vi.
|
||||
delete O[to];
|
||||
}
|
||||
}
|
||||
// Steps 20.c-d.
|
||||
// For packed arrays we can skip these steps: the fact that we don't
|
||||
// delete the elements one by one isn't visible to content code.
|
||||
if (!IsPackedArray(O)) {
|
||||
for (var k = len, kMin = len - actualDeleteCount + itemCount; k > kMin; k--)
|
||||
delete O[k - 1];
|
||||
}
|
||||
} else if (itemCount > actualDeleteCount) {
|
||||
// Step 21.
|
||||
// Steps 21 a-b.
|
||||
for (var k = len - actualDeleteCount, kMin = actualStart; k > kMin; k--) {
|
||||
// Step 21.b.i.
|
||||
var from = k + actualDeleteCount - 1;
|
||||
// Step 21.b.ii.
|
||||
var to = k + itemCount - 1;
|
||||
// Steps 21.b.iii-v.
|
||||
if (from in O) {
|
||||
O[to] = O[from];
|
||||
} else {
|
||||
// Step 21.b.vi.
|
||||
delete O[to];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 22-23.
|
||||
for (var k = actualStart, itemIndex = 2; itemIndex < numArgs; k++, itemIndex++)
|
||||
O[k] = arguments[itemIndex];
|
||||
|
||||
// Steps 24-25.
|
||||
O.length = len - actualDeleteCount + itemCount;
|
||||
|
||||
// Step 26.
|
||||
return A;
|
||||
}
|
||||
|
@ -70,8 +70,8 @@ function Number_isSafeInteger(number) {
|
||||
if (integer !== number)
|
||||
return false;
|
||||
|
||||
// Step 5. If abs(integer) <= 2**53 - 1, return true.
|
||||
if (std_Math_abs(integer) <= 9007199254740991)
|
||||
// Step 5.
|
||||
if (std_Math_abs(integer) <= 2 ** 53 - 1)
|
||||
return true;
|
||||
|
||||
// Step 6.
|
||||
|
@ -917,6 +917,25 @@ SaveStack(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CallFunctionFromNativeFrame(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() != 1) {
|
||||
JS_ReportError(cx, "The function takes exactly one argument.");
|
||||
return false;
|
||||
}
|
||||
if (!args[0].isObject() || !IsCallable(args[0])) {
|
||||
JS_ReportError(cx, "The first argument should be a function.");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject function(cx, &args[0].toObject());
|
||||
return Call(cx, UndefinedHandleValue, function,
|
||||
JS::HandleValueArray::empty(), args.rval());
|
||||
}
|
||||
|
||||
static bool
|
||||
CallFunctionWithAsyncStack(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
@ -2728,6 +2747,11 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
" of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n"
|
||||
" with the given object's compartment."),
|
||||
|
||||
JS_FN_HELP("callFunctionFromNativeFrame", CallFunctionFromNativeFrame, 1, 0,
|
||||
"callFunctionFromNativeFrame(function)",
|
||||
" Call 'function' with a (C++-)native frame on stack.\n"
|
||||
" Required for testing that SaveStack properly handles native frames."),
|
||||
|
||||
JS_FN_HELP("callFunctionWithAsyncStack", CallFunctionWithAsyncStack, 0, 0,
|
||||
"callFunctionWithAsyncStack(function, stack, asyncCause)",
|
||||
" Call 'function', using the provided stack as the async stack responsible\n"
|
||||
|
@ -110,8 +110,7 @@ function ToLength(v) {
|
||||
if (v <= 0)
|
||||
return 0;
|
||||
|
||||
// Math.pow(2, 53) - 1 = 0x1fffffffffffff
|
||||
return std_Math_min(v, 0x1fffffffffffff);
|
||||
return std_Math_min(v, 2 ** 53 - 1);
|
||||
}
|
||||
|
||||
/* Spec: ECMAScript Draft, 6th edition Oct 14, 2014, 7.2.4 */
|
||||
|
5
js/src/jit-test/tests/debug/bug-1192401.js
Normal file
5
js/src/jit-test/tests/debug/bug-1192401.js
Normal file
@ -0,0 +1,5 @@
|
||||
const dbg = new Debugger();
|
||||
const g = evalcx("lazy");
|
||||
dbg.addDebuggee(g);
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
g.eval("this.alloc = {}");
|
@ -245,6 +245,38 @@ function refuseAbs() {
|
||||
}
|
||||
test(refuseAbs);
|
||||
|
||||
function acceptFilterTypeSet() {
|
||||
var res = f32[0];
|
||||
if (!res) {
|
||||
} else {
|
||||
f32[0] = res;
|
||||
assertFloat32(res, true);
|
||||
}
|
||||
}
|
||||
test(acceptFilterTypeSet);
|
||||
|
||||
function acceptFilterTypeSet2() {
|
||||
var res = f32[0];
|
||||
if (!res) {
|
||||
} else {
|
||||
var res1 = Math.abs(res);
|
||||
f32[0] = res1;
|
||||
assertFloat32(res1, true);
|
||||
}
|
||||
}
|
||||
test(acceptFilterTypeSet2);
|
||||
|
||||
function refuseFilterTypeSet() {
|
||||
var res = f32[0];
|
||||
if (!res) {
|
||||
} else {
|
||||
var res1 = Math.abs(res);
|
||||
f64[0] = res1 + 1;
|
||||
assertFloat32(res1, false);
|
||||
}
|
||||
}
|
||||
test(refuseFilterTypeSet);
|
||||
|
||||
function refuseTrigo() {
|
||||
var res = Math.cos(f32[0]);
|
||||
f32[0] = res;
|
||||
|
@ -3,7 +3,7 @@
|
||||
// Unlike Array.prototype.map, Array.prototype.filter is not self-hosted.
|
||||
const filter = (function iife() {
|
||||
try {
|
||||
[3].filter(n => { throw saveStack() });
|
||||
callFunctionFromNativeFrame(n => { throw saveStack() });
|
||||
} catch (s) {
|
||||
return s;
|
||||
}
|
||||
|
@ -3438,18 +3438,6 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric* apply)
|
||||
emitPopArguments(apply, extraStackSpace);
|
||||
}
|
||||
|
||||
typedef bool (*ArraySpliceDenseFn)(JSContext*, HandleObject, uint32_t, uint32_t);
|
||||
static const VMFunction ArraySpliceDenseInfo = FunctionInfo<ArraySpliceDenseFn>(ArraySpliceDense);
|
||||
|
||||
void
|
||||
CodeGenerator::visitArraySplice(LArraySplice* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->getDeleteCount()));
|
||||
pushArg(ToRegister(lir->getStart()));
|
||||
pushArg(ToRegister(lir->getObject()));
|
||||
callVM(ArraySpliceDenseInfo, lir);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitBail(LBail* lir)
|
||||
{
|
||||
|
@ -216,7 +216,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void emitSetPropertyPolymorphic(LInstruction* lir, Register obj,
|
||||
Register scratch, const ConstantOrRegister& value);
|
||||
void visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins);
|
||||
void visitArraySplice(LArraySplice* splice);
|
||||
void visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins);
|
||||
void visitAbsI(LAbsI* lir);
|
||||
void visitAtan2D(LAtan2D* lir);
|
||||
|
@ -2985,7 +2985,7 @@ jit::ConvertLinearSum(TempAllocator& alloc, MBasicBlock* block, const LinearSum&
|
||||
if (term.scale == 1) {
|
||||
if (def) {
|
||||
def = MAdd::New(alloc, def, term.term);
|
||||
def->toAdd()->setInt32();
|
||||
def->toAdd()->setInt32Specialization();
|
||||
block->insertAtEnd(def->toInstruction());
|
||||
def->computeRange(alloc);
|
||||
} else {
|
||||
@ -2998,7 +2998,7 @@ jit::ConvertLinearSum(TempAllocator& alloc, MBasicBlock* block, const LinearSum&
|
||||
def->computeRange(alloc);
|
||||
}
|
||||
def = MSub::New(alloc, def, term.term);
|
||||
def->toSub()->setInt32();
|
||||
def->toSub()->setInt32Specialization();
|
||||
block->insertAtEnd(def->toInstruction());
|
||||
def->computeRange(alloc);
|
||||
} else {
|
||||
@ -3006,12 +3006,12 @@ jit::ConvertLinearSum(TempAllocator& alloc, MBasicBlock* block, const LinearSum&
|
||||
MConstant* factor = MConstant::New(alloc, Int32Value(term.scale));
|
||||
block->insertAtEnd(factor);
|
||||
MMul* mul = MMul::New(alloc, term.term, factor);
|
||||
mul->setInt32();
|
||||
mul->setInt32Specialization();
|
||||
block->insertAtEnd(mul);
|
||||
mul->computeRange(alloc);
|
||||
if (def) {
|
||||
def = MAdd::New(alloc, def, mul);
|
||||
def->toAdd()->setInt32();
|
||||
def->toAdd()->setInt32Specialization();
|
||||
block->insertAtEnd(def->toInstruction());
|
||||
def->computeRange(alloc);
|
||||
} else {
|
||||
@ -3026,7 +3026,7 @@ jit::ConvertLinearSum(TempAllocator& alloc, MBasicBlock* block, const LinearSum&
|
||||
constant->computeRange(alloc);
|
||||
if (def) {
|
||||
def = MAdd::New(alloc, def, constant);
|
||||
def->toAdd()->setInt32();
|
||||
def->toAdd()->setInt32Specialization();
|
||||
block->insertAtEnd(def->toInstruction());
|
||||
def->computeRange(alloc);
|
||||
} else {
|
||||
@ -3092,7 +3092,7 @@ jit::ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const Lin
|
||||
block->insertAtEnd(constant->toInstruction());
|
||||
constant->computeRange(alloc);
|
||||
lhsDef = MAdd::New(alloc, lhsDef, constant);
|
||||
lhsDef->toAdd()->setInt32();
|
||||
lhsDef->toAdd()->setInt32Specialization();
|
||||
block->insertAtEnd(lhsDef->toInstruction());
|
||||
lhsDef->computeRange(alloc);
|
||||
} while (false);
|
||||
|
@ -1656,7 +1656,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_MUL:
|
||||
case JSOP_DIV:
|
||||
case JSOP_MOD:
|
||||
return jsop_binary(op);
|
||||
return jsop_binary_arith(op);
|
||||
|
||||
case JSOP_POW:
|
||||
return jsop_pow();
|
||||
@ -4545,60 +4545,169 @@ IonBuilder::jsop_bitop(JSOp op)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_binary(JSOp op, MDefinition* left, MDefinition* right)
|
||||
MDefinition::Opcode
|
||||
JSOpToMDefinition(JSOp op)
|
||||
{
|
||||
// Do a string concatenation if adding two inputs that are int or string
|
||||
// and at least one is a string.
|
||||
if (op == JSOP_ADD &&
|
||||
((left->type() == MIRType_String &&
|
||||
(right->type() == MIRType_String ||
|
||||
right->type() == MIRType_Int32 ||
|
||||
right->type() == MIRType_Double)) ||
|
||||
(left->type() == MIRType_Int32 &&
|
||||
right->type() == MIRType_String) ||
|
||||
(left->type() == MIRType_Double &&
|
||||
right->type() == MIRType_String)))
|
||||
{
|
||||
MConcat* ins = MConcat::New(alloc(), left, right);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return maybeInsertResume();
|
||||
}
|
||||
|
||||
MBinaryArithInstruction* ins;
|
||||
switch (op) {
|
||||
case JSOP_ADD:
|
||||
ins = MAdd::New(alloc(), left, right);
|
||||
break;
|
||||
|
||||
return MDefinition::Op_Add;
|
||||
case JSOP_SUB:
|
||||
ins = MSub::New(alloc(), left, right);
|
||||
break;
|
||||
|
||||
return MDefinition::Op_Sub;
|
||||
case JSOP_MUL:
|
||||
ins = MMul::New(alloc(), left, right);
|
||||
break;
|
||||
|
||||
return MDefinition::Op_Mul;
|
||||
case JSOP_DIV:
|
||||
ins = MDiv::New(alloc(), left, right);
|
||||
break;
|
||||
|
||||
return MDefinition::Op_Div;
|
||||
case JSOP_MOD:
|
||||
ins = MMod::New(alloc(), left, right);
|
||||
break;
|
||||
|
||||
return MDefinition::Op_Mod;
|
||||
default:
|
||||
MOZ_CRASH("unexpected binary opcode");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDefinition* right)
|
||||
{
|
||||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
// Try to convert an addition into a concat operation if the inputs
|
||||
// indicate this might be a concatenation.
|
||||
|
||||
// Only try to replace this with concat when we have an addition.
|
||||
if (op != JSOP_ADD)
|
||||
return true;
|
||||
|
||||
// Make sure one of the inputs is a string.
|
||||
if (left->type() != MIRType_String && right->type() != MIRType_String)
|
||||
return true;
|
||||
|
||||
// The none-string input (if present) should be atleast a numerical type.
|
||||
// Which we can easily coerce to string.
|
||||
if (right->type() != MIRType_String && !IsNumberType(right->type()))
|
||||
return true;
|
||||
if (left->type() != MIRType_String && !IsNumberType(left->type()))
|
||||
return true;
|
||||
|
||||
MConcat* ins = MConcat::New(alloc(), left, right);
|
||||
current->add(ins);
|
||||
ins->infer(alloc(), inspector, pc);
|
||||
current->push(ins);
|
||||
|
||||
if (ins->isEffectful())
|
||||
return resumeAfter(ins);
|
||||
return maybeInsertResume();
|
||||
if (!maybeInsertResume())
|
||||
return false;
|
||||
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
SimpleArithOperand(MDefinition* op)
|
||||
{
|
||||
return !op->mightBeType(MIRType_Object)
|
||||
&& !op->mightBeType(MIRType_String)
|
||||
&& !op->mightBeType(MIRType_Symbol)
|
||||
&& !op->mightBeType(MIRType_MagicOptimizedArguments)
|
||||
&& !op->mightBeType(MIRType_MagicHole)
|
||||
&& !op->mightBeType(MIRType_MagicIsConstructing);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right)
|
||||
{
|
||||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
// Try to emit a specialized binary instruction based on the input types
|
||||
// of the operands.
|
||||
|
||||
// Anything complex - strings, symbols, and objects - are not specialized
|
||||
if (!SimpleArithOperand(left) || !SimpleArithOperand(right))
|
||||
return true;
|
||||
|
||||
// One of the inputs need to be a number.
|
||||
if (!IsNumberType(left->type()) && !IsNumberType(right->type()))
|
||||
return true;
|
||||
|
||||
MDefinition::Opcode defOp = JSOpToMDefinition(op);
|
||||
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), defOp, left, right);
|
||||
ins->setNumberSpecialization(alloc(), inspector, pc);
|
||||
|
||||
if (op == JSOP_ADD || op == JSOP_MUL)
|
||||
ins->setCommutative();
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
MOZ_ASSERT(!ins->isEffectful());
|
||||
if (!maybeInsertResume())
|
||||
return false;
|
||||
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op,
|
||||
MDefinition* left, MDefinition* right)
|
||||
{
|
||||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
// Try to emit a specialized binary instruction speculating the
|
||||
// type using the baseline caches.
|
||||
|
||||
MIRType specialization = inspector->expectedBinaryArithSpecialization(pc);
|
||||
if (specialization == MIRType_None)
|
||||
return true;
|
||||
|
||||
MDefinition::Opcode def_op = JSOpToMDefinition(op);
|
||||
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right);
|
||||
ins->setSpecialization(specialization);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
MOZ_ASSERT(!ins->isEffectful());
|
||||
if (!maybeInsertResume())
|
||||
return false;
|
||||
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right)
|
||||
{
|
||||
bool emitted = false;
|
||||
|
||||
if (!forceInlineCaches()) {
|
||||
if (!binaryArithTryConcat(&emitted, op, left, right) || emitted)
|
||||
return emitted;
|
||||
|
||||
if (!binaryArithTrySpecialized(&emitted, op, left, right) || emitted)
|
||||
return emitted;
|
||||
|
||||
if (!binaryArithTrySpecializedOnBaselineInspector(&emitted, op, left, right) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
// Not possible to optimize. Do a slow vm call.
|
||||
MDefinition::Opcode def_op = JSOpToMDefinition(op);
|
||||
MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right);
|
||||
|
||||
// Decrease type from 'any type' to 'empty type' when one of the operands
|
||||
// is 'empty typed'.
|
||||
maybeMarkEmpty(ins);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
MOZ_ASSERT(ins->isEffectful());
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_binary_arith(JSOp op)
|
||||
{
|
||||
MDefinition* right = current->pop();
|
||||
MDefinition* left = current->pop();
|
||||
|
||||
return jsop_binary_arith(op, left, right);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4620,15 +4729,6 @@ IonBuilder::jsop_pow()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_binary(JSOp op)
|
||||
{
|
||||
MDefinition* right = current->pop();
|
||||
MDefinition* left = current->pop();
|
||||
|
||||
return jsop_binary(op, left, right);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_pos()
|
||||
{
|
||||
@ -4645,7 +4745,7 @@ IonBuilder::jsop_pos()
|
||||
MConstant* one = MConstant::New(alloc(), Int32Value(1));
|
||||
current->add(one);
|
||||
|
||||
return jsop_binary(JSOP_MUL, value, one);
|
||||
return jsop_binary_arith(JSOP_MUL, value, one);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4658,7 +4758,7 @@ IonBuilder::jsop_neg()
|
||||
|
||||
MDefinition* right = current->pop();
|
||||
|
||||
if (!jsop_binary(JSOP_MUL, negator, right))
|
||||
if (!jsop_binary_arith(JSOP_MUL, negator, right))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@ -7166,6 +7266,24 @@ IonBuilder::maybeInsertResume()
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
void
|
||||
IonBuilder::maybeMarkEmpty(MDefinition* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->type() == MIRType_Value);
|
||||
|
||||
// When one of the operands has no type information, mark the output
|
||||
// as having no possible types too. This is to avoid degrading
|
||||
// subsequent analysis.
|
||||
for (size_t i = 0; i < ins->numOperands(); i++) {
|
||||
if (!ins->emptyResultTypeSet())
|
||||
continue;
|
||||
|
||||
TemporaryTypeSet* types = alloc().lifoAlloc()->new_<TemporaryTypeSet>();
|
||||
if (types)
|
||||
ins->setResultTypeSet(types);
|
||||
}
|
||||
}
|
||||
|
||||
// Return whether property lookups can be performed effectlessly on clasp.
|
||||
static bool
|
||||
ClassHasEffectlessLookup(const Class* clasp)
|
||||
|
@ -374,6 +374,8 @@ class IonBuilder
|
||||
// Creates a MDefinition based on the given def improved with type as TypeSet.
|
||||
MDefinition* ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types);
|
||||
|
||||
void maybeMarkEmpty(MDefinition* ins);
|
||||
|
||||
JSObject* getSingletonPrototype(JSFunction* target);
|
||||
|
||||
MDefinition* createThisScripted(MDefinition* callee);
|
||||
@ -481,6 +483,13 @@ class IonBuilder
|
||||
PropertyName* name, MDefinition* value,
|
||||
bool barrier, TemporaryTypeSet* objTypes);
|
||||
|
||||
// jsop_binary_arith helpers.
|
||||
MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right);
|
||||
bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
|
||||
bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
|
||||
bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
|
||||
MDefinition* right);
|
||||
|
||||
// binary data lookup helpers.
|
||||
TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
|
||||
TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
|
||||
@ -622,8 +631,8 @@ class IonBuilder
|
||||
bool jsop_add(MDefinition* left, MDefinition* right);
|
||||
bool jsop_bitnot();
|
||||
bool jsop_bitop(JSOp op);
|
||||
bool jsop_binary(JSOp op);
|
||||
bool jsop_binary(JSOp op, MDefinition* left, MDefinition* right);
|
||||
bool jsop_binary_arith(JSOp op);
|
||||
bool jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right);
|
||||
bool jsop_pow();
|
||||
bool jsop_pos();
|
||||
bool jsop_neg();
|
||||
@ -744,7 +753,6 @@ class IonBuilder
|
||||
InliningStatus inlineArrayConcat(CallInfo& callInfo);
|
||||
InliningStatus inlineArraySlice(CallInfo& callInfo);
|
||||
InliningStatus inlineArrayJoin(CallInfo& callInfo);
|
||||
InliningStatus inlineArraySplice(CallInfo& callInfo);
|
||||
|
||||
// Math natives.
|
||||
InliningStatus inlineMathAbs(CallInfo& callInfo);
|
||||
|
@ -556,16 +556,6 @@ LIRGenerator::visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* assertion
|
||||
MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitArraySplice(MArraySplice* ins)
|
||||
{
|
||||
LArraySplice* lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()),
|
||||
useRegisterAtStart(ins->start()),
|
||||
useRegisterAtStart(ins->deleteCount()));
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitGetDynamicName(MGetDynamicName* ins)
|
||||
{
|
||||
|
@ -99,7 +99,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitLoadArrowThis(MLoadArrowThis* ins);
|
||||
void visitCall(MCall* call);
|
||||
void visitApplyArgs(MApplyArgs* apply);
|
||||
void visitArraySplice(MArraySplice* splice);
|
||||
void visitBail(MBail* bail);
|
||||
void visitUnreachable(MUnreachable* unreachable);
|
||||
void visitEncodeSnapshot(MEncodeSnapshot* ins);
|
||||
|
@ -90,8 +90,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
||||
return inlineArrayConcat(callInfo);
|
||||
if (native == js::array_slice)
|
||||
return inlineArraySlice(callInfo);
|
||||
if (native == js::array_splice)
|
||||
return inlineArraySplice(callInfo);
|
||||
|
||||
// Math natives.
|
||||
if (native == js::math_abs)
|
||||
@ -693,46 +691,6 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineArraySplice(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Ensure |this|, argument and result are objects.
|
||||
if (getInlineReturnType() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.thisArg()->type() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.getArg(0)->type() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.getArg(1)->type() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
// Specialize arr.splice(start, deleteCount) with unused return value and
|
||||
// avoid creating the result array in this case.
|
||||
if (!BytecodeIsPopped(pc)) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MArraySplice* ins = MArraySplice::New(alloc(),
|
||||
callInfo.thisArg(),
|
||||
callInfo.getArg(0),
|
||||
callInfo.getArg(1));
|
||||
|
||||
current->add(ins);
|
||||
pushConstant(UndefinedValue());
|
||||
|
||||
if (!resumeAfter(ins))
|
||||
return InliningStatus_Error;
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineArrayJoin(CallInfo& callInfo)
|
||||
{
|
||||
@ -3429,7 +3387,7 @@ IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, M
|
||||
MAdd* addedIndex = MAdd::New(alloc(), *index, suppSlots);
|
||||
// We're fine even with the add overflows, as long as the generated code
|
||||
// for the bounds check uses an unsigned comparison.
|
||||
addedIndex->setInt32();
|
||||
addedIndex->setInt32Specialization();
|
||||
current->add(addedIndex);
|
||||
indexForBoundsCheck = addedIndex;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def, MInstruction*
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckUsesAreFloat32Consumers(MInstruction* ins)
|
||||
CheckUsesAreFloat32Consumers(const MInstruction* ins)
|
||||
{
|
||||
bool allConsumerUses = true;
|
||||
for (MUseDefIterator use(ins); allConsumerUses && use; use++)
|
||||
@ -113,6 +113,8 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt
|
||||
MDefinition* left = ins->getOperand(0);
|
||||
MDefinition* right = ins->getOperand(1);
|
||||
|
||||
MOZ_ASSERT(IsNumberType(left->type()) && IsNumberType(right->type()));
|
||||
|
||||
if (!left->isConstantValue() || !right->isConstantValue())
|
||||
return nullptr;
|
||||
|
||||
@ -2236,6 +2238,51 @@ NeedNegativeZeroCheck(MDefinition* def)
|
||||
return false;
|
||||
}
|
||||
|
||||
MBinaryArithInstruction*
|
||||
MBinaryArithInstruction::New(TempAllocator& alloc, Opcode op,
|
||||
MDefinition* left, MDefinition* right)
|
||||
{
|
||||
switch (op) {
|
||||
case Op_Add:
|
||||
return MAdd::New(alloc, left, right);
|
||||
case Op_Sub:
|
||||
return MSub::New(alloc, left, right);
|
||||
case Op_Mul:
|
||||
return MMul::New(alloc, left, right);
|
||||
case Op_Div:
|
||||
return MDiv::New(alloc, left, right);
|
||||
case Op_Mod:
|
||||
return MMod::New(alloc, left, right);
|
||||
default:
|
||||
MOZ_CRASH("unexpected binary opcode");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector,
|
||||
jsbytecode* pc)
|
||||
{
|
||||
setSpecialization(MIRType_Double);
|
||||
|
||||
// Try to specialize as int32.
|
||||
if (getOperand(0)->type() == MIRType_Int32 && getOperand(1)->type() == MIRType_Int32) {
|
||||
bool seenDouble = inspector->hasSeenDoubleResult(pc);
|
||||
|
||||
// Use int32 specialization if the operation doesn't overflow on its
|
||||
// constant operands and if the operation has never overflowed.
|
||||
if (!seenDouble && !constantDoubleResult(alloc))
|
||||
setInt32Specialization();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc)
|
||||
{
|
||||
bool typeChange = false;
|
||||
EvaluateConstantOperands(alloc, this, &typeChange);
|
||||
return typeChange;
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
MBinaryArithInstruction::foldsTo(TempAllocator& alloc)
|
||||
{
|
||||
@ -2276,6 +2323,23 @@ MBinaryArithInstruction::foldsTo(TempAllocator& alloc)
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
MFilterTypeSet::trySpecializeFloat32(TempAllocator& alloc)
|
||||
{
|
||||
MDefinition* in = input();
|
||||
if (in->type() != MIRType_Float32)
|
||||
return;
|
||||
|
||||
setResultType(MIRType_Float32);
|
||||
}
|
||||
|
||||
bool
|
||||
MFilterTypeSet::canConsumeFloat32(MUse* operand) const
|
||||
{
|
||||
MOZ_ASSERT(getUseFor(0) == operand);
|
||||
return CheckUsesAreFloat32Consumers(this);
|
||||
}
|
||||
|
||||
void
|
||||
MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc)
|
||||
{
|
||||
@ -2637,81 +2701,6 @@ SimpleArithOperand(MDefinition* op)
|
||||
&& !op->mightBeType(MIRType_MagicIsConstructing);
|
||||
}
|
||||
|
||||
void
|
||||
MBinaryArithInstruction::infer(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc)
|
||||
{
|
||||
MOZ_ASSERT(this->type() == MIRType_Value);
|
||||
|
||||
specialization_ = MIRType_None;
|
||||
|
||||
// Anything complex - strings, symbols, and objects - are not specialized
|
||||
// unless baseline type hints suggest it might be profitable
|
||||
if (!SimpleArithOperand(getOperand(0)) || !SimpleArithOperand(getOperand(1)))
|
||||
return inferFallback(inspector, pc);
|
||||
|
||||
// Retrieve type information of lhs and rhs.
|
||||
MIRType lhs = getOperand(0)->type();
|
||||
MIRType rhs = getOperand(1)->type();
|
||||
|
||||
// Guess a result type based on the inputs.
|
||||
// Don't specialize for neither-integer-nor-double results.
|
||||
if (lhs == MIRType_Int32 && rhs == MIRType_Int32) {
|
||||
setResultType(MIRType_Int32);
|
||||
|
||||
// If the operation will always overflow on its constant operands, use a
|
||||
// double specialization so that it can be constant folded later.
|
||||
if (isMul() || isDiv()) {
|
||||
bool typeChange = false;
|
||||
EvaluateConstantOperands(alloc, this, &typeChange);
|
||||
if (typeChange)
|
||||
setResultType(MIRType_Double);
|
||||
}
|
||||
|
||||
// If the operation has ever overflowed, use a double specialization.
|
||||
if (inspector->hasSeenDoubleResult(pc))
|
||||
setResultType(MIRType_Double);
|
||||
|
||||
} else if (IsFloatingPointType(lhs) || IsFloatingPointType(rhs)) {
|
||||
// Double operations take precedence over float32 operations (i.e. if
|
||||
// any operand needs a double as an input, convert all operands to
|
||||
// doubles)
|
||||
setResultType(MIRType_Double);
|
||||
} else {
|
||||
return inferFallback(inspector, pc);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(lhs < MIRType_String || lhs == MIRType_Value);
|
||||
MOZ_ASSERT(rhs < MIRType_String || rhs == MIRType_Value);
|
||||
|
||||
if (isAdd() || isMul())
|
||||
setCommutative();
|
||||
|
||||
MOZ_ASSERT(IsNumberType(this->type()));
|
||||
specialization_ = this->type();
|
||||
}
|
||||
|
||||
void
|
||||
MBinaryArithInstruction::inferFallback(BaselineInspector* inspector,
|
||||
jsbytecode* pc)
|
||||
{
|
||||
// Try to specialize based on what baseline observed in practice.
|
||||
specialization_ = inspector->expectedBinaryArithSpecialization(pc);
|
||||
if (specialization_ != MIRType_None) {
|
||||
setResultType(specialization_);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we can't specialize because we have no type information at all for
|
||||
// the lhs or rhs, mark the binary instruction as having no possible types
|
||||
// either to avoid degrading subsequent analysis.
|
||||
if (getOperand(0)->emptyResultTypeSet() || getOperand(1)->emptyResultTypeSet()) {
|
||||
LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc();
|
||||
TemporaryTypeSet* types = alloc->new_<TemporaryTypeSet>();
|
||||
if (types)
|
||||
setResultTypeSet(types);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
SafelyCoercesToDouble(MDefinition* op)
|
||||
{
|
||||
|
@ -852,7 +852,7 @@ class MDefinition : public MNode
|
||||
// iteration.
|
||||
class MUseDefIterator
|
||||
{
|
||||
MDefinition* def_;
|
||||
const MDefinition* def_;
|
||||
MUseIterator current_;
|
||||
|
||||
MUseIterator search(MUseIterator start) {
|
||||
@ -865,7 +865,7 @@ class MUseDefIterator
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MUseDefIterator(MDefinition* def)
|
||||
explicit MUseDefIterator(const MDefinition* def)
|
||||
: def_(def),
|
||||
current_(search(def->usesBegin()))
|
||||
{ }
|
||||
@ -3813,42 +3813,6 @@ class MCallDOMNative : public MCall
|
||||
virtual void computeMovable() override;
|
||||
};
|
||||
|
||||
// arr.splice(start, deleteCount) with unused return value.
|
||||
class MArraySplice
|
||||
: public MTernaryInstruction,
|
||||
public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
|
||||
{
|
||||
private:
|
||||
|
||||
MArraySplice(MDefinition* object, MDefinition* start, MDefinition* deleteCount)
|
||||
: MTernaryInstruction(object, start, deleteCount)
|
||||
{ }
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ArraySplice)
|
||||
static MArraySplice* New(TempAllocator& alloc, MDefinition* object,
|
||||
MDefinition* start, MDefinition* deleteCount)
|
||||
{
|
||||
return new(alloc) MArraySplice(object, start, deleteCount);
|
||||
}
|
||||
|
||||
MDefinition* object() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
MDefinition* start() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
MDefinition* deleteCount() const {
|
||||
return getOperand(2);
|
||||
}
|
||||
|
||||
bool possiblyCalls() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// fun.apply(self, arguments)
|
||||
class MApplyArgs
|
||||
: public MAryInstruction<3>,
|
||||
@ -5594,26 +5558,33 @@ class MBinaryArithInstruction
|
||||
// analysis detect a precision loss in the multiplication.
|
||||
TruncateKind implicitTruncate_;
|
||||
|
||||
void inferFallback(BaselineInspector* inspector, jsbytecode* pc);
|
||||
|
||||
public:
|
||||
MBinaryArithInstruction(MDefinition* left, MDefinition* right)
|
||||
: MBinaryInstruction(left, right),
|
||||
implicitTruncate_(NoTruncate)
|
||||
{
|
||||
specialization_ = MIRType_None;
|
||||
setMovable();
|
||||
}
|
||||
|
||||
static MBinaryArithInstruction* New(TempAllocator& alloc, Opcode op,
|
||||
MDefinition* left, MDefinition* right);
|
||||
|
||||
bool constantDoubleResult(TempAllocator& alloc);
|
||||
|
||||
MDefinition* foldsTo(TempAllocator& alloc) override;
|
||||
|
||||
virtual double getIdentity() = 0;
|
||||
|
||||
void infer(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
|
||||
|
||||
void setInt32() {
|
||||
void setSpecialization(MIRType type) {
|
||||
specialization_ = type;
|
||||
setResultType(type);
|
||||
}
|
||||
void setInt32Specialization() {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
}
|
||||
void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
|
||||
|
||||
virtual void trySpecializeFloat32(TempAllocator& alloc) override;
|
||||
|
||||
@ -12280,6 +12251,11 @@ class MFilterTypeSet
|
||||
return resultTypeSet()->empty();
|
||||
}
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
|
||||
bool isFloat32Commutative() const override { return true; }
|
||||
bool canProduceFloat32() const override { return input()->canProduceFloat32(); }
|
||||
bool canConsumeFloat32(MUse* operand) const override;
|
||||
void trySpecializeFloat32(TempAllocator& alloc) override;
|
||||
};
|
||||
|
||||
// Given a value, guard that the value is in a particular TypeSet, then returns
|
||||
|
@ -62,7 +62,6 @@ namespace jit {
|
||||
_(LoadArrowThis) \
|
||||
_(Call) \
|
||||
_(ApplyArgs) \
|
||||
_(ArraySplice) \
|
||||
_(Bail) \
|
||||
_(Unreachable) \
|
||||
_(EncodeSnapshot) \
|
||||
|
@ -251,18 +251,6 @@ StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res)
|
||||
template bool StringsEqual<true>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
|
||||
template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
|
||||
|
||||
bool
|
||||
ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount)
|
||||
{
|
||||
JS::AutoValueArray<4> argv(cx);
|
||||
argv[0].setUndefined();
|
||||
argv[1].setObject(*obj);
|
||||
argv[2].set(Int32Value(start));
|
||||
argv[3].set(Int32Value(deleteCount));
|
||||
|
||||
return js::array_splice_impl(cx, 2, argv.begin(), false);
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
|
@ -688,8 +688,6 @@ bool InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame
|
||||
JSObject* CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
|
||||
HandleObject owner, int32_t offset);
|
||||
|
||||
bool ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount);
|
||||
|
||||
bool Recompile(JSContext* cx);
|
||||
bool ForcedRecompile(JSContext* cx);
|
||||
JSString* RegExpReplace(JSContext* cx, HandleString string, HandleObject regexp,
|
||||
|
@ -959,6 +959,32 @@ public:
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void atomicExchange8SignExtend(const T& mem, Register value, Register output)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
template<typename T>
|
||||
void atomicExchange8ZeroExtend(const T& mem, Register value, Register output)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
template<typename T>
|
||||
void atomicExchange16SignExtend(const T& mem, Register value, Register output)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
template<typename T>
|
||||
void atomicExchange16ZeroExtend(const T& mem, Register value, Register output)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
template<typename T>
|
||||
void atomicExchange32(const T& mem, Register value, Register output)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
template<typename T, typename S>
|
||||
void atomicFetchAdd8SignExtend(const S& value, const T& mem, Register temp, Register output) {
|
||||
MOZ_CRASH("NYI");
|
||||
|
@ -1809,34 +1809,6 @@ class LApplyArgsGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES +
|
||||
}
|
||||
};
|
||||
|
||||
class LArraySplice : public LCallInstructionHelper<0, 3, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArraySplice)
|
||||
|
||||
LArraySplice(const LAllocation& object, const LAllocation& start,
|
||||
const LAllocation& deleteCount)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, start);
|
||||
setOperand(2, deleteCount);
|
||||
}
|
||||
|
||||
MArraySplice* mir() const {
|
||||
return mir_->toArraySplice();
|
||||
}
|
||||
|
||||
const LAllocation* getObject() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* getStart() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LAllocation* getDeleteCount() {
|
||||
return getOperand(2);
|
||||
}
|
||||
};
|
||||
|
||||
class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3>
|
||||
{
|
||||
public:
|
||||
|
@ -53,7 +53,6 @@
|
||||
_(NewArray) \
|
||||
_(NewArrayCopyOnWrite) \
|
||||
_(NewArrayDynamicLength) \
|
||||
_(ArraySplice) \
|
||||
_(NewObject) \
|
||||
_(NewTypedObject) \
|
||||
_(NewDeclEnvObject) \
|
||||
|
@ -61,6 +61,7 @@ MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due t
|
||||
MSG_DEF(JSMSG_BAD_WEAKMAP_KEY, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key")
|
||||
MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 1, JSEXN_TYPEERR, "invalid {0} usage")
|
||||
MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 0, JSEXN_RANGEERR, "invalid array length")
|
||||
MSG_DEF(JSMSG_BAD_ARRAY_LENGTH_SPLICE, 0, JSEXN_TYPEERR, "resulting array length too large")
|
||||
MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}")
|
||||
MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
|
||||
MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter")
|
||||
|
@ -28,8 +28,12 @@ BEGIN_TEST(testJitDCEinGVN_ins)
|
||||
block->add(p);
|
||||
MMul* mul0 = MMul::New(func.alloc, p, p, MIRType_Double);
|
||||
block->add(mul0);
|
||||
if (!mul0->typePolicy()->adjustInputs(func.alloc, mul0))
|
||||
return false;
|
||||
MMul* mul1 = MMul::New(func.alloc, mul0, mul0, MIRType_Double);
|
||||
block->add(mul1);
|
||||
if (!mul1->typePolicy()->adjustInputs(func.alloc, mul1))
|
||||
return false;
|
||||
MReturn* ret = MReturn::New(func.alloc, p);
|
||||
block->end(ret);
|
||||
|
||||
|
@ -28,6 +28,9 @@ BEGIN_TEST(testJitFoldsTo_DivReciprocal)
|
||||
block->add(c);
|
||||
MDiv* div = MDiv::New(func.alloc, p, c, MIRType_Double);
|
||||
block->add(div);
|
||||
if (!div->typePolicy()->adjustInputs(func.alloc, div))
|
||||
return false;
|
||||
MDefinition* left = div->getOperand(0);
|
||||
MReturn* ret = MReturn::New(func.alloc, div);
|
||||
block->end(ret);
|
||||
|
||||
@ -37,7 +40,7 @@ BEGIN_TEST(testJitFoldsTo_DivReciprocal)
|
||||
// Test that the div got folded to p * 0.25.
|
||||
MDefinition* op = ret->getOperand(0);
|
||||
CHECK(op->isMul());
|
||||
CHECK(op->getOperand(0) == p);
|
||||
CHECK(op->getOperand(0) == left);
|
||||
CHECK(op->getOperand(1)->isConstant());
|
||||
CHECK(op->getOperand(1)->toConstant()->value().toNumber() == 0.25);
|
||||
return true;
|
||||
@ -56,6 +59,10 @@ BEGIN_TEST(testJitFoldsTo_NoDivReciprocal)
|
||||
block->add(c);
|
||||
MDiv* div = MDiv::New(func.alloc, p, c, MIRType_Double);
|
||||
block->add(div);
|
||||
if (!div->typePolicy()->adjustInputs(func.alloc, div))
|
||||
return false;
|
||||
MDefinition* left = div->getOperand(0);
|
||||
MDefinition* right = div->getOperand(1);
|
||||
MReturn* ret = MReturn::New(func.alloc, div);
|
||||
block->end(ret);
|
||||
|
||||
@ -65,8 +72,8 @@ BEGIN_TEST(testJitFoldsTo_NoDivReciprocal)
|
||||
// Test that the div didn't get folded.
|
||||
MDefinition* op = ret->getOperand(0);
|
||||
CHECK(op->isDiv());
|
||||
CHECK(op->getOperand(0) == p);
|
||||
CHECK(op->getOperand(1) == c);
|
||||
CHECK(op->getOperand(0) == left);
|
||||
CHECK(op->getOperand(1) == right);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitFoldsTo_NoDivReciprocal)
|
||||
|
@ -579,7 +579,14 @@ js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
|
||||
// that element must prevent any deletions below it. Bug 586842 should
|
||||
// fix this inefficiency by moving indexed storage to be entirely
|
||||
// separate from non-indexed storage.
|
||||
if (!arr->isIndexed()) {
|
||||
// A second reason for this optimization to be invalid is an active
|
||||
// for..in iteration over the array. Keys deleted before being reached
|
||||
// during the iteration must not be visited, and suppressing them here
|
||||
// would be too costly.
|
||||
ObjectGroup* arrGroup = arr->getGroup(cx);
|
||||
if (!arr->isIndexed() &&
|
||||
!MOZ_UNLIKELY(!arrGroup || arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED)))
|
||||
{
|
||||
if (!arr->maybeCopyElementsForWrite(cx))
|
||||
return false;
|
||||
|
||||
@ -2254,277 +2261,6 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if this is a dense or unboxed array whose |count| properties
|
||||
* starting from |startingIndex| may be accessed (get, set, delete) directly
|
||||
* through its contiguous vector of elements without fear of getters, setters,
|
||||
* etc. along the prototype chain, or of enumerators requiring notification of
|
||||
* modifications.
|
||||
*/
|
||||
static inline bool
|
||||
CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t count, JSContext* cx)
|
||||
{
|
||||
/* If the desired properties overflow dense storage, we can't optimize. */
|
||||
if (UINT32_MAX - startingIndex < count)
|
||||
return false;
|
||||
|
||||
/* There's no optimizing possible if it's not an array. */
|
||||
if (!arr->is<ArrayObject>() && !arr->is<UnboxedArrayObject>())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Don't optimize if the array might be in the midst of iteration. We
|
||||
* rely on this to be able to safely move dense array elements around with
|
||||
* just a memmove (see NativeObject::moveDenseArrayElements), without worrying
|
||||
* about updating any in-progress enumerators for properties implicitly
|
||||
* deleted if a hole is moved from one location to another location not yet
|
||||
* visited. See bug 690622.
|
||||
*/
|
||||
ObjectGroup* arrGroup = arr->getGroup(cx);
|
||||
if (MOZ_UNLIKELY(!arrGroup || arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED)))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Another potential wrinkle: what if the enumeration is happening on an
|
||||
* object which merely has |arr| on its prototype chain?
|
||||
*/
|
||||
if (arr->isDelegate())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Now watch out for getters and setters along the prototype chain or in
|
||||
* other indexed properties on the object. (Note that non-writable length
|
||||
* is subsumed by the initializedLength comparison.)
|
||||
*/
|
||||
return !ObjectMayHaveExtraIndexedProperties(arr) &&
|
||||
startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr);
|
||||
}
|
||||
|
||||
/* ES5 15.4.4.12. */
|
||||
bool
|
||||
js::array_splice(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return array_splice_impl(cx, argc, vp, true);
|
||||
}
|
||||
|
||||
bool
|
||||
js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Step 1. */
|
||||
RootedObject obj(cx, ToObject(cx, args.thisv()));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Steps 3-4. */
|
||||
uint32_t len;
|
||||
if (!GetLengthProperty(cx, obj, &len))
|
||||
return false;
|
||||
|
||||
/* Step 5. */
|
||||
double relativeStart;
|
||||
if (!ToInteger(cx, args.get(0), &relativeStart))
|
||||
return false;
|
||||
|
||||
/* Step 6. */
|
||||
uint32_t actualStart;
|
||||
if (relativeStart < 0)
|
||||
actualStart = Max(len + relativeStart, 0.0);
|
||||
else
|
||||
actualStart = Min(relativeStart, double(len));
|
||||
|
||||
/* Step 7. */
|
||||
uint32_t actualDeleteCount;
|
||||
if (args.length() != 1) {
|
||||
double deleteCountDouble;
|
||||
RootedValue cnt(cx, args.length() >= 2 ? args[1] : Int32Value(0));
|
||||
if (!ToInteger(cx, cnt, &deleteCountDouble))
|
||||
return false;
|
||||
actualDeleteCount = Min(Max(deleteCountDouble, 0.0), double(len - actualStart));
|
||||
} else {
|
||||
/*
|
||||
* Non-standard: if start was specified but deleteCount was omitted,
|
||||
* delete to the end of the array. See bug 668024 for discussion.
|
||||
*/
|
||||
actualDeleteCount = len - actualStart;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(len - actualStart >= actualDeleteCount);
|
||||
|
||||
/* Steps 2, 8-9. */
|
||||
RootedObject arr(cx);
|
||||
if (CanOptimizeForDenseStorage(obj, actualStart, actualDeleteCount, cx)) {
|
||||
if (returnValueIsUsed) {
|
||||
arr = NewFullyAllocatedArrayTryReuseGroup(cx, obj, actualDeleteCount);
|
||||
if (!arr)
|
||||
return false;
|
||||
DebugOnly<DenseElementResult> result =
|
||||
CopyAnyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount);
|
||||
MOZ_ASSERT(result.value == DenseElementResult::Success);
|
||||
}
|
||||
} else {
|
||||
arr = NewFullyAllocatedArrayTryReuseGroup(cx, obj, actualDeleteCount);
|
||||
if (!arr)
|
||||
return false;
|
||||
|
||||
RootedValue fromValue(cx);
|
||||
for (uint32_t k = 0; k < actualDeleteCount; k++) {
|
||||
bool hole;
|
||||
if (!CheckForInterrupt(cx) ||
|
||||
!GetElement(cx, obj, actualStart + k, &hole, &fromValue) ||
|
||||
(!hole && !DefineElement(cx, arr, k, fromValue)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 11. */
|
||||
uint32_t itemCount = (args.length() >= 2) ? (args.length() - 2) : 0;
|
||||
|
||||
if (itemCount < actualDeleteCount) {
|
||||
/* Step 12: the array is being shrunk. */
|
||||
uint32_t sourceIndex = actualStart + actualDeleteCount;
|
||||
uint32_t targetIndex = actualStart + itemCount;
|
||||
uint32_t finalLength = len - actualDeleteCount + itemCount;
|
||||
|
||||
if (CanOptimizeForDenseStorage(obj, 0, len, cx)) {
|
||||
/* Steps 12(a)-(b). */
|
||||
DenseElementResult result =
|
||||
MoveAnyBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex,
|
||||
len - sourceIndex);
|
||||
MOZ_ASSERT(result != DenseElementResult::Incomplete);
|
||||
if (result == DenseElementResult::Failure)
|
||||
return false;
|
||||
|
||||
/* Steps 12(c)-(d). */
|
||||
SetAnyBoxedOrUnboxedInitializedLength(cx, obj, finalLength);
|
||||
} else {
|
||||
/*
|
||||
* This is all very slow if the length is very large. We don't yet
|
||||
* have the ability to iterate in sorted order, so we just do the
|
||||
* pessimistic thing and let CheckForInterrupt handle the
|
||||
* fallout.
|
||||
*/
|
||||
|
||||
/* Steps 12(a)-(b). */
|
||||
RootedValue fromValue(cx);
|
||||
for (uint32_t from = sourceIndex, to = targetIndex; from < len; from++, to++) {
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
bool hole;
|
||||
if (!GetElement(cx, obj, from, &hole, &fromValue))
|
||||
return false;
|
||||
if (hole) {
|
||||
if (!DeletePropertyOrThrow(cx, obj, to))
|
||||
return false;
|
||||
} else {
|
||||
if (!SetArrayElement(cx, obj, to, fromValue))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Steps 12(c)-(d). */
|
||||
for (uint32_t k = len; k > finalLength; k--) {
|
||||
if (!DeletePropertyOrThrow(cx, obj, k - 1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (itemCount > actualDeleteCount) {
|
||||
/* Step 13. */
|
||||
|
||||
/*
|
||||
* Optimize only if the array is already dense and we can extend it to
|
||||
* its new length. It would be wrong to extend the elements here for a
|
||||
* number of reasons.
|
||||
*
|
||||
* First, this could cause us to fall into the fast-path below. This
|
||||
* would cause elements to be moved into places past the non-writable
|
||||
* length. And when the dense initialized length is updated, that'll
|
||||
* cause the |in| operator to think that those elements actually exist,
|
||||
* even though, properly, setting them must fail.
|
||||
*
|
||||
* Second, extending the elements here will trigger assertions inside
|
||||
* ensureDenseElements that the elements aren't being extended past the
|
||||
* length of a non-writable array. This is because extending elements
|
||||
* will extend capacity -- which might extend them past a non-writable
|
||||
* length, violating the |capacity <= length| invariant for such
|
||||
* arrays. And that would make the various JITted fast-path method
|
||||
* implementations of [].push, [].unshift, and so on wrong.
|
||||
*
|
||||
* If the array length is non-writable, this method *will* throw. For
|
||||
* simplicity, have the slow-path code do it. (Also note that the slow
|
||||
* path may validly *not* throw -- if all the elements being moved are
|
||||
* holes.)
|
||||
*/
|
||||
if (obj->is<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
if (arr->lengthIsWritable()) {
|
||||
DenseElementResult result =
|
||||
arr->ensureDenseElements(cx, arr->length(), itemCount - actualDeleteCount);
|
||||
if (result == DenseElementResult::Failure)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) {
|
||||
DenseElementResult result =
|
||||
MoveAnyBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount,
|
||||
actualStart + actualDeleteCount,
|
||||
len - (actualStart + actualDeleteCount));
|
||||
MOZ_ASSERT(result != DenseElementResult::Incomplete);
|
||||
if (result == DenseElementResult::Failure)
|
||||
return false;
|
||||
|
||||
/* Steps 12(c)-(d). */
|
||||
SetAnyBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount);
|
||||
} else {
|
||||
RootedValue fromValue(cx);
|
||||
for (double k = len - actualDeleteCount; k > actualStart; k--) {
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
double from = k + actualDeleteCount - 1;
|
||||
double to = k + itemCount - 1;
|
||||
|
||||
bool hole;
|
||||
if (!GetElement(cx, obj, from, &hole, &fromValue))
|
||||
return false;
|
||||
|
||||
if (hole) {
|
||||
if (!DeletePropertyOrThrow(cx, obj, to))
|
||||
return false;
|
||||
} else {
|
||||
if (!SetArrayElement(cx, obj, to, fromValue))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 10. */
|
||||
Value* items = args.array() + 2;
|
||||
|
||||
/* Steps 14-15. */
|
||||
for (uint32_t k = actualStart, i = 0; i < itemCount; i++, k++) {
|
||||
if (!SetArrayElement(cx, obj, k, HandleValue::fromMarkedLocation(&items[i])))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Step 16. */
|
||||
double finalLength = double(len) - actualDeleteCount + itemCount;
|
||||
if (!SetLengthProperty(cx, obj, finalLength))
|
||||
return false;
|
||||
|
||||
/* Step 17. */
|
||||
if (returnValueIsUsed)
|
||||
args.rval().setObject(*arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <JSValueType Type>
|
||||
DenseElementResult
|
||||
ArrayConcatDenseKernel(JSContext* cx, JSObject* obj1, JSObject* obj2, JSObject* result)
|
||||
@ -2931,86 +2667,6 @@ js::array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t en
|
||||
return &argv[0].toObject();
|
||||
}
|
||||
|
||||
/* ES5 15.4.4.20. */
|
||||
static bool
|
||||
array_filter(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Step 1. */
|
||||
RootedObject obj(cx, ToObject(cx, args.thisv()));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
/* Step 2-3. */
|
||||
uint32_t len;
|
||||
if (!GetLengthProperty(cx, obj, &len))
|
||||
return false;
|
||||
|
||||
/* Step 4. */
|
||||
if (args.length() == 0) {
|
||||
ReportMissingArg(cx, args.calleev(), 0);
|
||||
return false;
|
||||
}
|
||||
RootedObject callable(cx, ValueToCallable(cx, args[0], args.length() - 1));
|
||||
if (!callable)
|
||||
return false;
|
||||
|
||||
/* Step 5. */
|
||||
RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
|
||||
|
||||
/* Step 6. */
|
||||
RootedObject arr(cx, NewFullyAllocatedArrayForCallingAllocationSite(cx, 0));
|
||||
if (!arr)
|
||||
return false;
|
||||
|
||||
/* Step 7. */
|
||||
uint32_t k = 0;
|
||||
|
||||
/* Step 8. */
|
||||
uint32_t to = 0;
|
||||
|
||||
/* Step 9. */
|
||||
FastInvokeGuard fig(cx, ObjectValue(*callable));
|
||||
InvokeArgs& args2 = fig.args();
|
||||
RootedValue kValue(cx);
|
||||
while (k < len) {
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
/* Step a, b, and c.i. */
|
||||
bool kNotPresent;
|
||||
if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
|
||||
return false;
|
||||
|
||||
/* Step c.ii-iii. */
|
||||
if (!kNotPresent) {
|
||||
if (!args2.init(3))
|
||||
return false;
|
||||
args2.setCallee(ObjectValue(*callable));
|
||||
args2.setThis(thisv);
|
||||
args2[0].set(kValue);
|
||||
args2[1].setNumber(k);
|
||||
args2[2].setObject(*obj);
|
||||
if (!fig.invoke(cx))
|
||||
return false;
|
||||
|
||||
if (ToBoolean(args2.rval())) {
|
||||
if (!SetArrayElement(cx, arr, to, kValue))
|
||||
return false;
|
||||
to++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step d. */
|
||||
k++;
|
||||
}
|
||||
|
||||
/* Step 10. */
|
||||
args.rval().setObject(*arr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
array_isArray(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
@ -3102,7 +2758,7 @@ static const JSFunctionSpec array_methods[] = {
|
||||
JS_FN("pop", array_pop, 0,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("shift", array_shift, 0,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_FN("splice", array_splice, 2,JSFUN_GENERIC_NATIVE),
|
||||
JS_SELF_HOSTED_FN("splice", "ArraySplice", 2,0),
|
||||
|
||||
/* Pythonic sequence methods. */
|
||||
JS_FN("concat", array_concat, 1,JSFUN_GENERIC_NATIVE),
|
||||
@ -3112,9 +2768,9 @@ static const JSFunctionSpec array_methods[] = {
|
||||
JS_SELF_HOSTED_FN("indexOf", "ArrayIndexOf", 1,0),
|
||||
JS_SELF_HOSTED_FN("forEach", "ArrayForEach", 1,0),
|
||||
JS_SELF_HOSTED_FN("map", "ArrayMap", 1,0),
|
||||
JS_SELF_HOSTED_FN("filter", "ArrayFilter", 1,0),
|
||||
JS_SELF_HOSTED_FN("reduce", "ArrayReduce", 1,0),
|
||||
JS_SELF_HOSTED_FN("reduceRight", "ArrayReduceRight", 1,0),
|
||||
JS_FN("filter", array_filter, 1,JSFUN_GENERIC_NATIVE),
|
||||
JS_SELF_HOSTED_FN("some", "ArraySome", 1,0),
|
||||
JS_SELF_HOSTED_FN("every", "ArrayEvery", 1,0),
|
||||
|
||||
@ -3143,6 +2799,7 @@ static const JSFunctionSpec array_static_methods[] = {
|
||||
JS_SELF_HOSTED_FN("indexOf", "ArrayStaticIndexOf", 2,0),
|
||||
JS_SELF_HOSTED_FN("forEach", "ArrayStaticForEach", 2,0),
|
||||
JS_SELF_HOSTED_FN("map", "ArrayStaticMap", 2,0),
|
||||
JS_SELF_HOSTED_FN("filter", "ArrayStaticFilter", 2,0),
|
||||
JS_SELF_HOSTED_FN("every", "ArrayStaticEvery", 2,0),
|
||||
JS_SELF_HOSTED_FN("some", "ArrayStaticSome", 2,0),
|
||||
JS_SELF_HOSTED_FN("reduce", "ArrayStaticReduce", 2,0),
|
||||
|
10
js/src/tests/ecma/Array/array-length-set-during-for-in.js
Normal file
10
js/src/tests/ecma/Array/array-length-set-during-for-in.js
Normal file
@ -0,0 +1,10 @@
|
||||
var a = [0, 1];
|
||||
var iterations = 0;
|
||||
for (var k in a) {
|
||||
iterations++;
|
||||
a.length = 1;
|
||||
}
|
||||
assertEq(iterations, 1);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
14
js/src/tests/ecma_6/Array/splice_length_overflow_throws.js
Normal file
14
js/src/tests/ecma_6/Array/splice_length_overflow_throws.js
Normal file
@ -0,0 +1,14 @@
|
||||
var a = {};
|
||||
a[2 ** 53 - 2] = 1;
|
||||
a.length = 2 ** 53 - 1;
|
||||
|
||||
var exception;
|
||||
try {
|
||||
[].splice.call(a, 2 ** 53 - 2, 0, 2, 3, 4, 5);
|
||||
} catch (e) {
|
||||
exception = e;
|
||||
}
|
||||
reportCompare(a[2 ** 53 - 2], 1);
|
||||
reportCompare(a.length, 2 ** 53 - 1);
|
||||
reportCompare(exception instanceof TypeError, true, "Array#splice throws TypeError for length overflows");
|
||||
reportCompare(exception.message.indexOf('array length') > -1, true, "Array#splice throws correct error for length overflows");
|
@ -901,7 +901,10 @@ SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame, unsi
|
||||
MOZ_ASSERT(initialized());
|
||||
assertSameCompartment(cx, this);
|
||||
|
||||
if (creatingSavedFrame || cx->isExceptionPending()) {
|
||||
if (creatingSavedFrame ||
|
||||
cx->isExceptionPending() ||
|
||||
!cx->global()->isStandardClassResolved(JSProto_Object))
|
||||
{
|
||||
frame.set(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
@ -29,11 +29,11 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 299;
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 300;
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||
|
||||
static_assert(JSErr_Limit == 407,
|
||||
static_assert(JSErr_Limit == 408,
|
||||
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
|
||||
"removed MSG_DEFs from js.msg, you should increment "
|
||||
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
|
||||
|
@ -873,7 +873,10 @@ nsRangeFrame::GetAdditionalStyleContext(int32_t aIndex) const
|
||||
// We only implement this so that SetAdditionalStyleContext will be
|
||||
// called if style changes that would change the -moz-focus-outer
|
||||
// pseudo-element have occurred.
|
||||
return aIndex == 0 ? mOuterFocusStyle : nullptr;
|
||||
if (aIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return mOuterFocusStyle;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -66,6 +66,7 @@ let windows_versions = [
|
||||
// Possible values for '-moz-windows-theme'
|
||||
let windows_themes = [
|
||||
"aero",
|
||||
"aero-lite",
|
||||
"luna-blue",
|
||||
"luna-olive",
|
||||
"luna-silver",
|
||||
@ -119,14 +120,17 @@ let testToggles = function (resisting) {
|
||||
// __testWindowsSpecific__.
|
||||
// Runs a media query on the queryName with the given possible matching values.
|
||||
let testWindowsSpecific = function (resisting, queryName, possibleValues) {
|
||||
let found = false;
|
||||
let foundValue = null;
|
||||
possibleValues.forEach(function (val) {
|
||||
found = found || keyValMatches(queryName, val);
|
||||
if (keyValMatches(queryName, val)) {
|
||||
foundValue = val;
|
||||
}
|
||||
});
|
||||
if (resisting) {
|
||||
ok(!found, queryName + " should have no match");
|
||||
ok(!foundValue, queryName + " should have no match");
|
||||
} else {
|
||||
ok(found, queryName + " should match");
|
||||
ok(foundValue, foundValue ? ("Match found: '" + queryName + ":" + foundValue + "'")
|
||||
: "Should have a match for '" + queryName + "'");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -703,7 +703,15 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
ASSERT_EQ(expected_local_type_, local->type);
|
||||
ASSERT_EQ(expected_local_transport_, local->local_addr.transport);
|
||||
DumpCandidate("Remote ", *remote);
|
||||
ASSERT_EQ(expected_remote_type_, remote->type);
|
||||
/* Remote ICE TCP active candidates are always trickled with port 9
|
||||
so they will get discovered as peer reflexive locally. */
|
||||
if (expected_local_transport_ == kNrIceTransportTcp &&
|
||||
expected_remote_type_ == NrIceCandidate::ICE_HOST) {
|
||||
ASSERT_NE(NrIceCandidate::ICE_SERVER_REFLEXIVE, remote->type);
|
||||
ASSERT_NE(NrIceCandidate::ICE_RELAYED, remote->type);
|
||||
} else {
|
||||
ASSERT_EQ(expected_remote_type_, remote->type);
|
||||
}
|
||||
if (!expected_remote_addr_.empty()) {
|
||||
ASSERT_EQ(expected_remote_addr_, remote->cand_addr.host);
|
||||
}
|
||||
|
@ -532,6 +532,22 @@
|
||||
# define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
|
||||
#endif /* MOZ_CLANG_PLUGIN */
|
||||
|
||||
/*
|
||||
* MOZ_HAVE_REF_QUALIFIERS is defined for compilers that support C++11's rvalue
|
||||
* qualifier, "&&".
|
||||
*/
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
# define MOZ_HAVE_REF_QUALIFIERS
|
||||
#elif defined(__clang__)
|
||||
// All supported Clang versions
|
||||
# define MOZ_HAVE_REF_QUALIFIERS
|
||||
#elif defined(__GNUC__)
|
||||
# include "mozilla/Compiler.h"
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 1)
|
||||
# define MOZ_HAVE_REF_QUALIFIERS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* mozilla_Attributes_h */
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/RefCountType.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
#include "nsXPCOM.h"
|
||||
@ -278,10 +279,23 @@ public:
|
||||
}
|
||||
|
||||
T* get() const { return mPtr; }
|
||||
operator T*() const { return mPtr; }
|
||||
operator T*() const
|
||||
#ifdef MOZ_HAVE_REF_QUALIFIERS
|
||||
&
|
||||
#endif
|
||||
{ return mPtr; }
|
||||
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mPtr; }
|
||||
T& operator*() const { return *mPtr; }
|
||||
|
||||
#ifdef MOZ_HAVE_REF_QUALIFIERS
|
||||
// Don't allow implicit conversion of temporary RefPtr to raw pointer, because
|
||||
// the refcount might be one and the pointer will immediately become invalid.
|
||||
operator T*() const && = delete;
|
||||
|
||||
// Needed to avoid the deleted operator above
|
||||
explicit operator bool() const { return !!mPtr; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
void assign(T* aVal)
|
||||
{
|
||||
@ -375,4 +389,19 @@ MakeAndAddRef(Args&&... aArgs)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Declared in nsRefPtr.h
|
||||
template<class T> template<class U>
|
||||
nsRefPtr<T>::nsRefPtr(mozilla::RefPtr<U>&& aOther)
|
||||
: nsRefPtr(aOther.forget())
|
||||
{
|
||||
}
|
||||
|
||||
template<class T> template<class U>
|
||||
nsRefPtr<T>&
|
||||
nsRefPtr<T>::operator=(mozilla::RefPtr<U>&& aOther)
|
||||
{
|
||||
assign_assuming_AddRef(aOther.forget().take());
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif /* mozilla_RefPtr_h */
|
||||
|
@ -19,6 +19,7 @@ class nsCOMPtr_helper;
|
||||
|
||||
namespace mozilla {
|
||||
template<class T> class OwningNonNull;
|
||||
template<class T> class RefPtr;
|
||||
} // namespace mozilla
|
||||
|
||||
template <class T>
|
||||
@ -127,6 +128,10 @@ public:
|
||||
template<class U>
|
||||
MOZ_IMPLICIT nsRefPtr(const mozilla::OwningNonNull<U>& aOther);
|
||||
|
||||
// Defined in RefPtr.h
|
||||
template<class U>
|
||||
MOZ_IMPLICIT nsRefPtr(mozilla::RefPtr<U>&& aOther);
|
||||
|
||||
// Assignment operators
|
||||
|
||||
nsRefPtr<T>&
|
||||
@ -187,6 +192,11 @@ public:
|
||||
nsRefPtr<T>&
|
||||
operator=(const mozilla::OwningNonNull<U>& aOther);
|
||||
|
||||
// Defined in RefPtr.h
|
||||
template<class U>
|
||||
nsRefPtr<T>&
|
||||
operator=(mozilla::RefPtr<U>&& aOther);
|
||||
|
||||
// Other pointer operators
|
||||
|
||||
void
|
||||
@ -241,6 +251,9 @@ public:
|
||||
}
|
||||
|
||||
operator T*() const
|
||||
#ifdef MOZ_HAVE_REF_QUALIFIERS
|
||||
&
|
||||
#endif
|
||||
/*
|
||||
...makes an |nsRefPtr| act like its underlying raw pointer type whenever it
|
||||
is used in a context where a raw pointer is expected. It is this operator
|
||||
@ -253,6 +266,19 @@ public:
|
||||
return get();
|
||||
}
|
||||
|
||||
#ifdef MOZ_HAVE_REF_QUALIFIERS
|
||||
// Don't allow implicit conversion of temporary nsRefPtr to raw pointer,
|
||||
// because the refcount might be one and the pointer will immediately become
|
||||
// invalid.
|
||||
operator T*() const && = delete;
|
||||
|
||||
// These are needed to avoid the deleted operator above. XXX Why is operator!
|
||||
// needed separately? Shouldn't the compiler prefer using the non-deleted
|
||||
// operator bool instead of the deleted operator T*?
|
||||
explicit operator bool() const { return !!mRawPtr; }
|
||||
bool operator!() const { return !mRawPtr; }
|
||||
#endif
|
||||
|
||||
T*
|
||||
operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
|
||||
{
|
||||
|
@ -771,7 +771,8 @@ nsCertTree::DeleteEntryObject(uint32_t index)
|
||||
if (certdi->mAddonInfo) {
|
||||
cert = certdi->mAddonInfo->mCert;
|
||||
}
|
||||
nsCertAddonInfo *addonInfo = certdi->mAddonInfo ? certdi->mAddonInfo : nullptr;
|
||||
nsCertAddonInfo* addonInfo =
|
||||
certdi->mAddonInfo ? certdi->mAddonInfo.get() : nullptr;
|
||||
if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) {
|
||||
mOverrideService->ClearValidityOverride(certdi->mAsciiHost, certdi->mPort);
|
||||
if (addonInfo) {
|
||||
|
@ -190,37 +190,56 @@ InstallSigSysHandler(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* This function installs the syscall filter, a.k.a. seccomp.
|
||||
* PR_SET_NO_NEW_PRIVS ensures that it is impossible to grant more
|
||||
* syscalls to the process beyond this point (even after fork()).
|
||||
* This function installs the syscall filter, a.k.a. seccomp. The
|
||||
* aUseTSync flag indicates whether this should apply to all threads
|
||||
* in the process -- which will fail if the kernel doesn't support
|
||||
* that -- or only the current thread.
|
||||
*
|
||||
* SECCOMP_MODE_FILTER is the "bpf" mode of seccomp which allows
|
||||
* to pass a bpf program (in our case, it contains a syscall
|
||||
* whitelist).
|
||||
*
|
||||
* Reports failure by crashing.
|
||||
* PR_SET_NO_NEW_PRIVS ensures that it is impossible to grant more
|
||||
* syscalls to the process beyond this point (even after fork()), and
|
||||
* prevents gaining capabilities (e.g., by exec'ing a setuid root
|
||||
* program). The kernel won't allow seccomp-bpf without doing this,
|
||||
* because otherwise it could be used for privilege escalation attacks.
|
||||
*
|
||||
* @see sock_fprog (the seccomp_prog).
|
||||
* Returns false (and sets errno) on failure.
|
||||
*
|
||||
* @see SandboxInfo
|
||||
* @see BroadcastSetThreadSandbox
|
||||
*/
|
||||
static void
|
||||
InstallSyscallFilter(const sock_fprog *prog)
|
||||
static bool MOZ_WARN_UNUSED_RESULT
|
||||
InstallSyscallFilter(const sock_fprog *aProg, bool aUseTSync)
|
||||
{
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
||||
SANDBOX_LOG_ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %s", strerror(errno));
|
||||
MOZ_CRASH("prctl(PR_SET_NO_NEW_PRIVS)");
|
||||
}
|
||||
|
||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)prog, 0, 0)) {
|
||||
SANDBOX_LOG_ERROR("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) failed: %s",
|
||||
strerror(errno));
|
||||
MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
|
||||
if (aUseTSync) {
|
||||
if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
|
||||
SECCOMP_FILTER_FLAG_TSYNC, aProg) != 0) {
|
||||
SANDBOX_LOG_ERROR("thread-synchronized seccomp failed: %s",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)aProg, 0, 0)) {
|
||||
SANDBOX_LOG_ERROR("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) failed: %s",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use signals for permissions that need to be set per-thread.
|
||||
// The communication channel from the signal handler back to the main thread.
|
||||
static mozilla::Atomic<int> gSetSandboxDone;
|
||||
// Pass the filter itself through a global.
|
||||
static sock_fprog gSetSandboxFilter;
|
||||
static const sock_fprog* gSetSandboxFilter;
|
||||
|
||||
// We have to dynamically allocate the signal number; see bug 1038900.
|
||||
// This function returns the first realtime signal currently set to
|
||||
@ -250,7 +269,9 @@ static bool
|
||||
SetThreadSandbox()
|
||||
{
|
||||
if (prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
|
||||
InstallSyscallFilter(&gSetSandboxFilter);
|
||||
if (!InstallSyscallFilter(gSetSandboxFilter, false)) {
|
||||
MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -273,19 +294,25 @@ SetThreadSandboxHandler(int signum)
|
||||
}
|
||||
|
||||
static void
|
||||
BroadcastSetThreadSandbox(UniquePtr<sock_filter[]> aProgram, size_t aProgLen)
|
||||
EnterChroot()
|
||||
{
|
||||
if (gChrootHelper) {
|
||||
gChrootHelper->Invoke();
|
||||
gChrootHelper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
BroadcastSetThreadSandbox(const sock_fprog* aFilter)
|
||||
{
|
||||
int signum;
|
||||
pid_t pid, tid, myTid;
|
||||
DIR *taskdp;
|
||||
struct dirent *de;
|
||||
|
||||
// Note: this is an unsafe copy of the unique pointer, but it's
|
||||
// zeroed (and the signal handler that would access it is removed)
|
||||
// before the end of this function.
|
||||
gSetSandboxFilter.filter = aProgram.get();
|
||||
gSetSandboxFilter.len = static_cast<unsigned short>(aProgLen);
|
||||
MOZ_RELEASE_ASSERT(static_cast<size_t>(gSetSandboxFilter.len) == aProgLen);
|
||||
// This function does not own *aFilter, so this global needs to
|
||||
// always be zeroed before returning.
|
||||
gSetSandboxFilter = aFilter;
|
||||
|
||||
static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
|
||||
"mozilla::Atomic<int> isn't represented by an int");
|
||||
@ -297,10 +324,7 @@ BroadcastSetThreadSandbox(UniquePtr<sock_filter[]> aProgram, size_t aProgLen)
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
if (gChrootHelper) {
|
||||
gChrootHelper->Invoke();
|
||||
gChrootHelper = nullptr;
|
||||
}
|
||||
EnterChroot();
|
||||
|
||||
signum = FindFreeSignalNumber();
|
||||
if (signum == 0) {
|
||||
@ -416,7 +440,20 @@ BroadcastSetThreadSandbox(UniquePtr<sock_filter[]> aProgram, size_t aProgLen)
|
||||
unused << closedir(taskdp);
|
||||
// And now, deprivilege the main thread:
|
||||
SetThreadSandbox();
|
||||
gSetSandboxFilter.filter = nullptr;
|
||||
gSetSandboxFilter = nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
ApplySandboxWithTSync(sock_fprog* aFilter)
|
||||
{
|
||||
EnterChroot();
|
||||
// At this point we're committed to using tsync, because the signal
|
||||
// broadcast workaround needs to access procfs. (Unless chroot
|
||||
// isn't used... but this failure shouldn't happen in the first
|
||||
// place, so let's not make extra special cases for it.)
|
||||
if (!InstallSyscallFilter(aFilter, true)) {
|
||||
MOZ_CRASH("seccomp+tsync failed, but kernel supports tsync");
|
||||
}
|
||||
}
|
||||
|
||||
// Common code for sandbox startup.
|
||||
@ -445,12 +482,30 @@ SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy)
|
||||
#endif
|
||||
|
||||
// The syscall takes a C-style array, so copy the vector into one.
|
||||
UniquePtr<sock_filter[]> flatProgram(new sock_filter[program->size()]);
|
||||
size_t programLen = program->size();
|
||||
UniquePtr<sock_filter[]> flatProgram(new sock_filter[programLen]);
|
||||
for (auto i = program->begin(); i != program->end(); ++i) {
|
||||
flatProgram[i - program->begin()] = *i;
|
||||
}
|
||||
|
||||
BroadcastSetThreadSandbox(Move(flatProgram), program->size());
|
||||
sock_fprog fprog;
|
||||
fprog.filter = flatProgram.get();
|
||||
fprog.len = static_cast<unsigned short>(programLen);
|
||||
MOZ_RELEASE_ASSERT(static_cast<size_t>(fprog.len) == programLen);
|
||||
|
||||
const SandboxInfo info = SandboxInfo::Get();
|
||||
if (info.Test(SandboxInfo::kHasSeccompTSync)) {
|
||||
if (info.Test(SandboxInfo::kVerbose)) {
|
||||
SANDBOX_LOG_ERROR("using seccomp tsync");
|
||||
}
|
||||
ApplySandboxWithTSync(&fprog);
|
||||
} else {
|
||||
if (info.Test(SandboxInfo::kVerbose)) {
|
||||
SANDBOX_LOG_ERROR("no tsync support; using signal broadcast");
|
||||
}
|
||||
BroadcastSetThreadSandbox(&fprog);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(!gChrootHelper, "forgot to chroot");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -46,6 +46,7 @@ SandboxChroot::SendCommand(Command aComm)
|
||||
{
|
||||
MOZ_ALWAYS_ZERO(pthread_mutex_lock(&mMutex));
|
||||
if (mCommand == NO_THREAD) {
|
||||
MOZ_RELEASE_ASSERT(aComm == JUST_EXIT);
|
||||
MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
|
||||
return false;
|
||||
} else {
|
||||
|
@ -28,6 +28,29 @@ class unknown(object):
|
||||
return 'UNKNOWN'
|
||||
unknown = unknown() # singleton
|
||||
|
||||
def get_windows_version():
|
||||
import ctypes
|
||||
class OSVERSIONINFOEXW(ctypes.Structure):
|
||||
_fields_ = [('dwOSVersionInfoSize', ctypes.c_ulong),
|
||||
('dwMajorVersion', ctypes.c_ulong),
|
||||
('dwMinorVersion', ctypes.c_ulong),
|
||||
('dwBuildNumber', ctypes.c_ulong),
|
||||
('dwPlatformId', ctypes.c_ulong),
|
||||
('szCSDVersion', ctypes.c_wchar*128),
|
||||
('wServicePackMajor', ctypes.c_ushort),
|
||||
('wServicePackMinor', ctypes.c_ushort),
|
||||
('wSuiteMask', ctypes.c_ushort),
|
||||
('wProductType', ctypes.c_byte),
|
||||
('wReserved', ctypes.c_byte)]
|
||||
|
||||
os_version = OSVERSIONINFOEXW()
|
||||
os_version.dwOSVersionInfoSize = ctypes.sizeof(os_version)
|
||||
retcode = ctypes.windll.Ntdll.RtlGetVersion(ctypes.byref(os_version))
|
||||
if retcode != 0:
|
||||
raise OSError
|
||||
|
||||
return os_version.dwMajorVersion, os_version.dwMinorVersion, os_version.dwBuildNumber
|
||||
|
||||
# get system information
|
||||
info = {'os': unknown,
|
||||
'processor': unknown,
|
||||
@ -50,6 +73,14 @@ if system in ["Microsoft", "Windows"]:
|
||||
system = os.environ.get("OS", system).replace('_', ' ')
|
||||
(major, minor, _, _, service_pack) = os.sys.getwindowsversion()
|
||||
info['service_pack'] = service_pack
|
||||
if major >= 6 and minor >= 2:
|
||||
# On windows >= 8.1 the system call that getwindowsversion uses has
|
||||
# been frozen to always return the same values. In this case we call
|
||||
# the RtlGetVersion API directly, which still provides meaningful
|
||||
# values, at least for now.
|
||||
major, minor, build_number = get_windows_version()
|
||||
version = "%d.%d.%d" % (major, minor, build_number)
|
||||
|
||||
os_version = "%d.%d" % (major, minor)
|
||||
elif system == "Linux":
|
||||
if hasattr(platform, "linux_distribution"):
|
||||
|
@ -51,6 +51,9 @@ config = {
|
||||
("browser/config/mozconfigs/macosx-universal/nightly",
|
||||
"ac_add_options --with-branding=browser/branding/nightly",
|
||||
"ac_add_options --with-branding=browser/branding/aurora"),
|
||||
("browser/config/mozconfigs/macosx-universal/l10n-mozconfig",
|
||||
"ac_add_options --with-branding=browser/branding/nightly",
|
||||
"ac_add_options --with-branding=browser/branding/aurora"),
|
||||
("browser/config/mozconfigs/whitelist",
|
||||
"ac_add_options --with-branding=browser/branding/nightly",
|
||||
"ac_add_options --with-branding=browser/branding/aurora"),
|
||||
|
94
testing/mozharness/external_tools/gittool.py
Executable file
94
testing/mozharness/external_tools/gittool.py
Executable file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user