summaryrefslogtreecommitdiff
path: root/xpcom/reflect/xptinfo
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/reflect/xptinfo')
-rw-r--r--xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp700
-rw-r--r--xpcom/reflect/xptinfo/ShimInterfaceInfo.h50
-rw-r--r--xpcom/reflect/xptinfo/TODO20
-rw-r--r--xpcom/reflect/xptinfo/XPTInterfaceInfoManager.h119
-rw-r--r--xpcom/reflect/xptinfo/moz.build37
-rw-r--r--xpcom/reflect/xptinfo/nsIInterfaceInfo.idl101
-rw-r--r--xpcom/reflect/xptinfo/nsIInterfaceInfoManager.idl28
-rw-r--r--xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp742
-rw-r--r--xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp242
-rw-r--r--xpcom/reflect/xptinfo/xptiTypelibGuts.cpp74
-rw-r--r--xpcom/reflect/xptinfo/xptiWorkingSet.cpp53
-rw-r--r--xpcom/reflect/xptinfo/xptinfo.h236
-rw-r--r--xpcom/reflect/xptinfo/xptiprivate.h394
13 files changed, 2796 insertions, 0 deletions
diff --git a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
new file mode 100644
index 0000000000..14e719f6c4
--- /dev/null
+++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
@@ -0,0 +1,700 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ShimInterfaceInfo.h"
+
+#include "nsIBrowserBoxObject.h"
+#include "nsIContainerBoxObject.h"
+#include "nsIDOMAnimationEvent.h"
+#include "nsIDOMAttr.h"
+#include "nsIDOMBeforeUnloadEvent.h"
+#include "nsIDOMCanvasRenderingContext2D.h"
+#include "nsIDOMCDATASection.h"
+#include "nsIDOMCharacterData.h"
+#include "nsIDOMClientRect.h"
+#include "nsIDOMClientRectList.h"
+#include "nsIDOMClipboardEvent.h"
+#include "nsIDOMCommandEvent.h"
+#include "nsIDOMComment.h"
+#include "nsIDOMCSSPrimitiveValue.h"
+#include "nsIDOMCSSStyleDeclaration.h"
+#include "nsIDOMCSSStyleSheet.h"
+#include "nsIDOMCSSValue.h"
+#include "nsIDOMCSSValueList.h"
+#include "nsIDOMCustomEvent.h"
+#include "nsIDOMDataContainerEvent.h"
+#ifdef MOZ_WEBRTC
+#include "nsIDOMDataChannel.h"
+#endif
+#include "nsIDOMDataTransfer.h"
+#include "nsIDOMDOMCursor.h"
+#include "nsIDOMDOMException.h"
+#include "nsIDOMDOMRequest.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMDocumentFragment.h"
+#include "nsIDOMDocumentType.h"
+#include "nsIDOMDocumentXBL.h"
+#include "nsIDOMDragEvent.h"
+#include "nsIDOMElement.h"
+#include "nsIDOMEvent.h"
+#include "nsIDOMEventTarget.h"
+#include "nsIDOMFileList.h"
+#include "nsIDOMFocusEvent.h"
+#include "nsIDOMFormData.h"
+#include "nsIDOMGeoPositionError.h"
+#include "nsIDOMHistory.h"
+#include "nsIDOMHTMLAnchorElement.h"
+#include "nsIDOMHTMLAppletElement.h"
+#include "nsIDOMHTMLAreaElement.h"
+#include "nsIDOMHTMLBaseElement.h"
+#include "nsIDOMHTMLBodyElement.h"
+#include "nsIDOMHTMLButtonElement.h"
+#include "nsIDOMHTMLCanvasElement.h"
+#include "nsIDOMHTMLCollection.h"
+#include "nsIDOMHTMLDirectoryElement.h"
+#include "nsIDOMHTMLDocument.h"
+#include "nsIDOMHTMLElement.h"
+#include "nsIDOMHTMLEmbedElement.h"
+#include "nsIDOMHTMLFieldSetElement.h"
+#include "nsIDOMHTMLFormElement.h"
+#include "nsIDOMHTMLFrameElement.h"
+#include "nsIDOMHTMLFrameSetElement.h"
+#include "nsIDOMHTMLHRElement.h"
+#include "nsIDOMHTMLHeadElement.h"
+#include "nsIDOMHTMLHtmlElement.h"
+#include "nsIDOMHTMLIFrameElement.h"
+#include "nsIDOMHTMLImageElement.h"
+#include "nsIDOMHTMLInputElement.h"
+#include "nsIDOMHTMLLIElement.h"
+#include "nsIDOMHTMLLabelElement.h"
+#include "nsIDOMHTMLLinkElement.h"
+#include "nsIDOMHTMLMapElement.h"
+#include "nsIDOMHTMLMediaElement.h"
+#include "nsIDOMHTMLMenuElement.h"
+#include "nsIDOMHTMLMenuItemElement.h"
+#include "nsIDOMHTMLMetaElement.h"
+#include "nsIDOMHTMLOListElement.h"
+#include "nsIDOMHTMLObjectElement.h"
+#include "nsIDOMHTMLOptGroupElement.h"
+#include "nsIDOMHTMLOptionElement.h"
+#include "nsIDOMHTMLOptionsCollection.h"
+#include "nsIDOMHTMLParagraphElement.h"
+#include "nsIDOMHTMLPreElement.h"
+#include "nsIDOMHTMLQuoteElement.h"
+#include "nsIDOMHTMLScriptElement.h"
+#include "nsIDOMHTMLSelectElement.h"
+#include "nsIDOMHTMLSourceElement.h"
+#include "nsIDOMHTMLStyleElement.h"
+#include "nsIDOMHTMLTableCellElement.h"
+#include "nsIDOMHTMLTextAreaElement.h"
+#include "nsIDOMHTMLUListElement.h"
+#include "nsIDOMKeyEvent.h"
+#include "nsIDOMMediaList.h"
+#include "nsIDOMMouseEvent.h"
+#include "nsIDOMMouseScrollEvent.h"
+#include "nsIDOMMutationEvent.h"
+#include "nsIDOMMozNamedAttrMap.h"
+#include "nsIDOMNode.h"
+#include "nsIDOMNodeIterator.h"
+#include "nsIDOMNotifyPaintEvent.h"
+#include "nsIDOMNSEvent.h"
+#include "nsIDOMOfflineResourceList.h"
+#include "nsIDOMPaintRequest.h"
+#include "nsIDOMParser.h"
+#include "nsIDOMProcessingInstruction.h"
+#include "nsIDOMRange.h"
+#include "nsIDOMRect.h"
+#include "nsIDOMScreen.h"
+#include "nsIDOMScrollAreaEvent.h"
+#include "nsIDOMSerializer.h"
+#include "nsIDOMSimpleGestureEvent.h"
+#include "nsIDOMStyleSheet.h"
+#include "nsIDOMStyleSheetList.h"
+#include "nsIDOMSVGElement.h"
+#include "nsIDOMSVGLength.h"
+#include "nsIDOMText.h"
+#include "nsIDOMTimeEvent.h"
+#include "nsIDOMTimeRanges.h"
+#include "nsIDOMTransitionEvent.h"
+#include "nsIDOMTreeWalker.h"
+#include "nsIDOMUIEvent.h"
+#include "nsIDOMValidityState.h"
+#include "nsIDOMWheelEvent.h"
+#include "nsIDOMXMLDocument.h"
+#include "nsIDOMXPathEvaluator.h"
+#include "nsIDOMXPathResult.h"
+#include "nsIDOMXULCommandEvent.h"
+#include "nsIDOMXULDocument.h"
+#include "nsIDOMXULElement.h"
+#include "nsIListBoxObject.h"
+#include "nsIMenuBoxObject.h"
+#include "nsIScrollBoxObject.h"
+#include "nsISelection.h"
+#include "nsITreeBoxObject.h"
+#include "nsIXMLHttpRequest.h"
+
+#include "mozilla/dom/AnimationEventBinding.h"
+#include "mozilla/dom/AttrBinding.h"
+#include "mozilla/dom/BeforeUnloadEventBinding.h"
+#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
+#include "mozilla/dom/CDATASectionBinding.h"
+#include "mozilla/dom/CharacterDataBinding.h"
+#include "mozilla/dom/DOMRectBinding.h"
+#include "mozilla/dom/DOMRectListBinding.h"
+#include "mozilla/dom/ClipboardEventBinding.h"
+#include "mozilla/dom/CommandEventBinding.h"
+#include "mozilla/dom/CommentBinding.h"
+#include "mozilla/dom/ContainerBoxObjectBinding.h"
+#include "mozilla/dom/CSSPrimitiveValueBinding.h"
+#include "mozilla/dom/CSSStyleDeclarationBinding.h"
+#include "mozilla/dom/CSSStyleSheetBinding.h"
+#include "mozilla/dom/CSSValueBinding.h"
+#include "mozilla/dom/CSSValueListBinding.h"
+#include "mozilla/dom/CustomEventBinding.h"
+#ifdef MOZ_WEBRTC
+#include "mozilla/dom/DataChannelBinding.h"
+#endif
+#include "mozilla/dom/DataContainerEventBinding.h"
+#include "mozilla/dom/DataTransferBinding.h"
+#include "mozilla/dom/DOMCursorBinding.h"
+#include "mozilla/dom/DOMExceptionBinding.h"
+#include "mozilla/dom/DOMParserBinding.h"
+#include "mozilla/dom/DOMRequestBinding.h"
+#include "mozilla/dom/DocumentBinding.h"
+#include "mozilla/dom/DocumentFragmentBinding.h"
+#include "mozilla/dom/DocumentTypeBinding.h"
+#include "mozilla/dom/DocumentBinding.h"
+#include "mozilla/dom/DragEventBinding.h"
+#include "mozilla/dom/ElementBinding.h"
+#include "mozilla/dom/EventBinding.h"
+#include "mozilla/dom/EventTargetBinding.h"
+#include "mozilla/dom/FileListBinding.h"
+#include "mozilla/dom/FocusEventBinding.h"
+#include "mozilla/dom/FormDataBinding.h"
+#include "mozilla/dom/HistoryBinding.h"
+#include "mozilla/dom/HTMLAnchorElementBinding.h"
+#include "mozilla/dom/HTMLAppletElementBinding.h"
+#include "mozilla/dom/HTMLAreaElementBinding.h"
+#include "mozilla/dom/HTMLBaseElementBinding.h"
+#include "mozilla/dom/HTMLBodyElementBinding.h"
+#include "mozilla/dom/HTMLButtonElementBinding.h"
+#include "mozilla/dom/HTMLCanvasElementBinding.h"
+#include "mozilla/dom/HTMLCollectionBinding.h"
+#include "mozilla/dom/HTMLDirectoryElementBinding.h"
+#include "mozilla/dom/HTMLDocumentBinding.h"
+#include "mozilla/dom/HTMLElementBinding.h"
+#include "mozilla/dom/HTMLEmbedElementBinding.h"
+#include "mozilla/dom/HTMLFieldSetElementBinding.h"
+#include "mozilla/dom/HTMLFormElementBinding.h"
+#include "mozilla/dom/HTMLFrameElementBinding.h"
+#include "mozilla/dom/HTMLFrameSetElementBinding.h"
+#include "mozilla/dom/HTMLHRElementBinding.h"
+#include "mozilla/dom/HTMLHeadElementBinding.h"
+#include "mozilla/dom/HTMLHtmlElementBinding.h"
+#include "mozilla/dom/HTMLIFrameElementBinding.h"
+#include "mozilla/dom/HTMLImageElementBinding.h"
+#include "mozilla/dom/HTMLInputElementBinding.h"
+#include "mozilla/dom/HTMLLIElementBinding.h"
+#include "mozilla/dom/HTMLLabelElementBinding.h"
+#include "mozilla/dom/HTMLLinkElementBinding.h"
+#include "mozilla/dom/HTMLMapElementBinding.h"
+#include "mozilla/dom/HTMLMediaElementBinding.h"
+#include "mozilla/dom/HTMLMenuElementBinding.h"
+#include "mozilla/dom/HTMLMenuItemElementBinding.h"
+#include "mozilla/dom/HTMLMetaElementBinding.h"
+#include "mozilla/dom/HTMLOListElementBinding.h"
+#include "mozilla/dom/HTMLObjectElementBinding.h"
+#include "mozilla/dom/HTMLOptGroupElementBinding.h"
+#include "mozilla/dom/HTMLOptionElementBinding.h"
+#include "mozilla/dom/HTMLOptionsCollectionBinding.h"
+#include "mozilla/dom/HTMLParagraphElementBinding.h"
+#include "mozilla/dom/HTMLPreElementBinding.h"
+#include "mozilla/dom/HTMLQuoteElementBinding.h"
+#include "mozilla/dom/HTMLScriptElementBinding.h"
+#include "mozilla/dom/HTMLSelectElementBinding.h"
+#include "mozilla/dom/HTMLSourceElementBinding.h"
+#include "mozilla/dom/HTMLStyleElementBinding.h"
+#include "mozilla/dom/HTMLTableCellElementBinding.h"
+#include "mozilla/dom/HTMLTextAreaElementBinding.h"
+#include "mozilla/dom/HTMLUListElementBinding.h"
+#include "mozilla/dom/KeyEventBinding.h"
+#include "mozilla/dom/ListBoxObjectBinding.h"
+#include "mozilla/dom/MediaListBinding.h"
+#include "mozilla/dom/MessageEventBinding.h"
+#include "mozilla/dom/MenuBoxObjectBinding.h"
+#include "mozilla/dom/MouseEventBinding.h"
+#include "mozilla/dom/MouseScrollEventBinding.h"
+#include "mozilla/dom/MutationEventBinding.h"
+#include "mozilla/dom/NamedNodeMapBinding.h"
+#include "mozilla/dom/NodeIteratorBinding.h"
+#include "mozilla/dom/NodeBinding.h"
+#include "mozilla/dom/NotifyPaintEventBinding.h"
+#include "mozilla/dom/EventBinding.h"
+#include "mozilla/dom/OfflineResourceListBinding.h"
+#include "mozilla/dom/PaintRequestBinding.h"
+#include "mozilla/dom/PositionErrorBinding.h"
+#include "mozilla/dom/ProcessingInstructionBinding.h"
+#include "mozilla/dom/RangeBinding.h"
+#include "mozilla/dom/RectBinding.h"
+#include "mozilla/dom/ScreenBinding.h"
+#include "mozilla/dom/ScrollBoxObjectBinding.h"
+#include "mozilla/dom/SelectionBinding.h"
+#include "mozilla/dom/ScrollAreaEventBinding.h"
+#include "mozilla/dom/SimpleGestureEventBinding.h"
+#include "mozilla/dom/StorageEventBinding.h"
+#include "mozilla/dom/StyleSheetBinding.h"
+#include "mozilla/dom/StyleSheetListBinding.h"
+#include "mozilla/dom/SVGElementBinding.h"
+#include "mozilla/dom/SVGLengthBinding.h"
+#include "mozilla/dom/TextBinding.h"
+#include "mozilla/dom/TimeEventBinding.h"
+#include "mozilla/dom/TimeRangesBinding.h"
+#include "mozilla/dom/TransitionEventBinding.h"
+#include "mozilla/dom/TreeBoxObjectBinding.h"
+#include "mozilla/dom/TreeWalkerBinding.h"
+#include "mozilla/dom/UIEventBinding.h"
+#include "mozilla/dom/ValidityStateBinding.h"
+#include "mozilla/dom/WheelEventBinding.h"
+#include "mozilla/dom/XMLDocumentBinding.h"
+#include "mozilla/dom/XMLHttpRequestEventTargetBinding.h"
+#include "mozilla/dom/XMLHttpRequestUploadBinding.h"
+#include "mozilla/dom/XMLSerializerBinding.h"
+#include "mozilla/dom/XPathEvaluatorBinding.h"
+#include "mozilla/dom/XPathResultBinding.h"
+#include "mozilla/dom/XULCommandEventBinding.h"
+#include "mozilla/dom/XULDocumentBinding.h"
+#include "mozilla/dom/XULElementBinding.h"
+
+using namespace mozilla;
+
+struct ComponentsInterfaceShimEntry {
+ constexpr
+ ComponentsInterfaceShimEntry(const char* aName, const nsIID& aIID,
+ const dom::NativePropertyHooks* aNativePropHooks)
+ : geckoName(aName), iid(aIID), nativePropHooks(aNativePropHooks) {}
+
+ const char *geckoName;
+ const nsIID& iid;
+ const dom::NativePropertyHooks* nativePropHooks;
+};
+
+#define DEFINE_SHIM_WITH_CUSTOM_INTERFACE(geckoName, domName) \
+ { #geckoName, NS_GET_IID(geckoName), \
+ mozilla::dom::domName ## Binding::sNativePropertyHooks }
+#define DEFINE_SHIM(name) \
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOM ## name, name)
+
+/**
+ * These shim entries allow us to make old XPIDL interfaces implementing DOM
+ * APIs as non-scriptable in order to save some runtime memory on Firefox OS,
+ * without breaking the entries under Components.interfaces which might both
+ * be used by our code and add-ons. Specifically, the shim entries provide
+ * the following:
+ *
+ * * Components.interfaces.nsIFoo entries. These entries basically work
+ * almost exactly as the usual ones that you would get through the
+ * XPIDL machinery. Specifically, they have the right name, they reflect
+ * the right IID, and they will work properly when passed to QueryInterface.
+ *
+ * * Components.interfaces.nsIFoo.CONSTANT values. These entries will have
+ * the right name and the right value for most integer types. Note that
+ * support for non-numerical constants is untested and will probably not
+ * work out of the box.
+ *
+ * FAQ:
+ * * When should I add an entry to the list here?
+ * Only if you're making an XPIDL interfaces which has a corresponding
+ * WebIDL interface non-scriptable.
+ * * When should I remove an entry from this list?
+ * If you are completely removing an XPIDL interface from the code base. If
+ * you forget to do so, the compiler will remind you.
+ * * How should I add an entry to the list here?
+ * First, make sure that the XPIDL interface in question is non-scriptable
+ * and also has a corresponding WebIDL interface. Then, add two include
+ * entries above, one for the XPIDL interface and one for the WebIDL
+ * interface, and add a shim entry below. If the name of the XPIDL
+ * interface only has an "nsIDOM" prefix prepended to the WebIDL name, you
+ * can use the DEFINE_SHIM macro and pass in the name of the WebIDL
+ * interface. Otherwise, use DEFINE_SHIM_WITH_CUSTOM_INTERFACE.
+ */
+
+const ComponentsInterfaceShimEntry kComponentsInterfaceShimMap[] =
+{
+ DEFINE_SHIM(AnimationEvent),
+ DEFINE_SHIM(Attr),
+ DEFINE_SHIM(BeforeUnloadEvent),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIBrowserBoxObject, ContainerBoxObject),
+ DEFINE_SHIM(CanvasRenderingContext2D),
+ DEFINE_SHIM(CDATASection),
+ DEFINE_SHIM(CharacterData),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMClientRect, DOMRectReadOnly),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMClientRectList, DOMRectList),
+ DEFINE_SHIM(ClipboardEvent),
+ DEFINE_SHIM(CommandEvent),
+ DEFINE_SHIM(Comment),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIContainerBoxObject, ContainerBoxObject),
+ DEFINE_SHIM(CSSPrimitiveValue),
+ DEFINE_SHIM(CSSStyleDeclaration),
+ DEFINE_SHIM(CSSStyleSheet),
+ DEFINE_SHIM(CSSValue),
+ DEFINE_SHIM(CSSValueList),
+ DEFINE_SHIM(CustomEvent),
+#ifdef MOZ_WEBRTC
+ DEFINE_SHIM(DataChannel),
+#endif
+ DEFINE_SHIM(DataContainerEvent),
+ DEFINE_SHIM(DataTransfer),
+ DEFINE_SHIM(DOMCursor),
+ DEFINE_SHIM(DOMException),
+ DEFINE_SHIM(DOMRequest),
+ DEFINE_SHIM(Document),
+ DEFINE_SHIM(DocumentFragment),
+ DEFINE_SHIM(DocumentType),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMDocumentXBL, Document),
+ DEFINE_SHIM(DragEvent),
+ DEFINE_SHIM(Element),
+ DEFINE_SHIM(Event),
+ DEFINE_SHIM(EventTarget),
+ DEFINE_SHIM(FileList),
+ DEFINE_SHIM(FocusEvent),
+ DEFINE_SHIM(FormData),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMGeoPositionError, PositionError),
+ DEFINE_SHIM(History),
+ DEFINE_SHIM(HTMLAnchorElement),
+ DEFINE_SHIM(HTMLAppletElement),
+ DEFINE_SHIM(HTMLAreaElement),
+ DEFINE_SHIM(HTMLBaseElement),
+ DEFINE_SHIM(HTMLBodyElement),
+ DEFINE_SHIM(HTMLButtonElement),
+ DEFINE_SHIM(HTMLCanvasElement),
+ DEFINE_SHIM(HTMLCollection),
+ DEFINE_SHIM(HTMLDirectoryElement),
+ DEFINE_SHIM(HTMLDocument),
+ DEFINE_SHIM(HTMLElement),
+ DEFINE_SHIM(HTMLEmbedElement),
+ DEFINE_SHIM(HTMLFieldSetElement),
+ DEFINE_SHIM(HTMLFormElement),
+ DEFINE_SHIM(HTMLFrameElement),
+ DEFINE_SHIM(HTMLFrameSetElement),
+ DEFINE_SHIM(HTMLHRElement),
+ DEFINE_SHIM(HTMLHeadElement),
+ DEFINE_SHIM(HTMLHtmlElement),
+ DEFINE_SHIM(HTMLIFrameElement),
+ DEFINE_SHIM(HTMLImageElement),
+ DEFINE_SHIM(HTMLInputElement),
+ DEFINE_SHIM(HTMLLIElement),
+ DEFINE_SHIM(HTMLLabelElement),
+ DEFINE_SHIM(HTMLLinkElement),
+ DEFINE_SHIM(HTMLMapElement),
+ DEFINE_SHIM(HTMLMediaElement),
+ DEFINE_SHIM(HTMLMenuElement),
+ DEFINE_SHIM(HTMLMenuItemElement),
+ DEFINE_SHIM(HTMLMetaElement),
+ DEFINE_SHIM(HTMLOListElement),
+ DEFINE_SHIM(HTMLObjectElement),
+ DEFINE_SHIM(HTMLOptGroupElement),
+ DEFINE_SHIM(HTMLOptionElement),
+ DEFINE_SHIM(HTMLOptionsCollection),
+ DEFINE_SHIM(HTMLParagraphElement),
+ DEFINE_SHIM(HTMLPreElement),
+ DEFINE_SHIM(HTMLQuoteElement),
+ DEFINE_SHIM(HTMLScriptElement),
+ DEFINE_SHIM(HTMLSelectElement),
+ DEFINE_SHIM(HTMLSourceElement),
+ DEFINE_SHIM(HTMLStyleElement),
+ DEFINE_SHIM(HTMLTableCellElement),
+ DEFINE_SHIM(HTMLTextAreaElement),
+ DEFINE_SHIM(HTMLUListElement),
+ DEFINE_SHIM(KeyEvent),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIListBoxObject, ListBoxObject),
+ DEFINE_SHIM(MediaList),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIMenuBoxObject, MenuBoxObject),
+ DEFINE_SHIM(MouseEvent),
+ DEFINE_SHIM(MouseScrollEvent),
+ DEFINE_SHIM(MutationEvent),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMMozNamedAttrMap, NamedNodeMap),
+ DEFINE_SHIM(NodeIterator),
+ DEFINE_SHIM(Node),
+ DEFINE_SHIM(NotifyPaintEvent),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMNSEvent, Event),
+ DEFINE_SHIM(OfflineResourceList),
+ DEFINE_SHIM(PaintRequest),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMParser, DOMParser),
+ DEFINE_SHIM(ProcessingInstruction),
+ DEFINE_SHIM(Range),
+ DEFINE_SHIM(Rect),
+ DEFINE_SHIM(Screen),
+ DEFINE_SHIM(ScrollAreaEvent),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIScrollBoxObject, ScrollBoxObject),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMSerializer, XMLSerializer),
+ DEFINE_SHIM(SimpleGestureEvent),
+ DEFINE_SHIM(StyleSheet),
+ DEFINE_SHIM(StyleSheetList),
+ DEFINE_SHIM(SVGElement),
+ DEFINE_SHIM(SVGLength),
+ DEFINE_SHIM(Text),
+ DEFINE_SHIM(TimeEvent),
+ DEFINE_SHIM(TimeRanges),
+ DEFINE_SHIM(TransitionEvent),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsITreeBoxObject, TreeBoxObject),
+ DEFINE_SHIM(TreeWalker),
+ DEFINE_SHIM(UIEvent),
+ DEFINE_SHIM(ValidityState),
+ DEFINE_SHIM(WheelEvent),
+ DEFINE_SHIM(XMLDocument),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIXMLHttpRequestEventTarget, XMLHttpRequestEventTarget),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIXMLHttpRequestUpload, XMLHttpRequestUpload),
+ DEFINE_SHIM(XPathEvaluator),
+ DEFINE_SHIM(XPathResult),
+ DEFINE_SHIM(XULCommandEvent),
+ DEFINE_SHIM(XULDocument),
+ DEFINE_SHIM(XULElement),
+ DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsISelection, Selection),
+};
+
+#undef DEFINE_SHIM
+#undef DEFINE_SHIM_WITH_CUSTOM_INTERFACE
+
+NS_IMPL_ISUPPORTS(ShimInterfaceInfo, nsISupports, nsIInterfaceInfo)
+
+already_AddRefed<ShimInterfaceInfo>
+ShimInterfaceInfo::MaybeConstruct(const char* aName, JSContext* cx)
+{
+ RefPtr<ShimInterfaceInfo> info;
+ for (uint32_t i = 0; i < ArrayLength(kComponentsInterfaceShimMap); ++i) {
+ if (!strcmp(aName, kComponentsInterfaceShimMap[i].geckoName)) {
+ const ComponentsInterfaceShimEntry& shimEntry =
+ kComponentsInterfaceShimMap[i];
+ info = new ShimInterfaceInfo(shimEntry.iid,
+ shimEntry.geckoName,
+ shimEntry.nativePropHooks);
+ break;
+ }
+ }
+ return info.forget();
+}
+
+ShimInterfaceInfo::ShimInterfaceInfo(const nsIID& aIID,
+ const char* aName,
+ const mozilla::dom::NativePropertyHooks* aNativePropHooks)
+ : mIID(aIID)
+ , mName(aName)
+ , mNativePropHooks(aNativePropHooks)
+{
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetName(char** aName)
+{
+ *aName = ToNewCString(mName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetInterfaceIID(nsIID** aIID)
+{
+ *aIID = static_cast<nsIID*> (nsMemory::Clone(&mIID, sizeof(mIID)));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::IsScriptable(bool* aRetVal)
+{
+ // This class should pretend that the interface is scriptable because
+ // that's what nsJSIID assumes.
+ *aRetVal = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::IsBuiltinClass(bool* aRetVal)
+{
+ *aRetVal = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::IsMainProcessScriptableOnly(bool* aRetVal)
+{
+ *aRetVal = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetParent(nsIInterfaceInfo** aParent)
+{
+ *aParent = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetMethodCount(uint16_t* aCount)
+{
+ // Pretend we don't have any methods.
+ *aCount = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetConstantCount(uint16_t* aCount)
+{
+ // We assume that we never have interfaces with more than UINT16_MAX
+ // constants defined on them.
+ uint16_t count = 0;
+
+ // NOTE: The structure of this loop must be kept in sync with the loop
+ // in GetConstant.
+ const mozilla::dom::NativePropertyHooks* propHooks = mNativePropHooks;
+ do {
+ const mozilla::dom::NativeProperties* props[] = {
+ propHooks->mNativeProperties.regular,
+ propHooks->mNativeProperties.chromeOnly
+ };
+ for (size_t i = 0; i < ArrayLength(props); ++i) {
+ auto prop = props[i];
+ if (prop && prop->HasConstants()) {
+ for (auto cs = prop->Constants()->specs; cs->name; ++cs) {
+ // We have found one constant here. We explicitly do not
+ // bother calling isEnabled() here because it's OK to define
+ // potentially extra constants on these shim interfaces.
+ ++count;
+ }
+ }
+ }
+ } while ((propHooks = propHooks->mProtoHooks));
+ *aCount = count;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetMethodInfo(uint16_t aIndex, const nsXPTMethodInfo** aInfo)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetMethodInfoForName(const char* aName, uint16_t* aIndex, const nsXPTMethodInfo** aInfo)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetConstant(uint16_t aIndex, JS::MutableHandleValue aConstant,
+ char** aName)
+{
+ // We assume that we never have interfaces with more than UINT16_MAX
+ // constants defined on them.
+ uint16_t index = 0;
+
+ // NOTE: The structure of this loop must be kept in sync with the loop
+ // in GetConstantCount.
+ const mozilla::dom::NativePropertyHooks* propHooks = mNativePropHooks;
+ do {
+ const mozilla::dom::NativeProperties* props[] = {
+ propHooks->mNativeProperties.regular,
+ propHooks->mNativeProperties.chromeOnly
+ };
+ for (size_t i = 0; i < ArrayLength(props); ++i) {
+ auto prop = props[i];
+ if (prop && prop->HasConstants()) {
+ for (auto cs = prop->Constants()->specs; cs->name; ++cs) {
+ // We have found one constant here. We explicitly do not
+ // bother calling isEnabled() here because it's OK to define
+ // potentially extra constants on these shim interfaces.
+ if (index == aIndex) {
+ aConstant.set(cs->value);
+ *aName = ToNewCString(nsDependentCString(cs->name));
+ return NS_OK;
+ }
+ ++index;
+ }
+ }
+ }
+ } while ((propHooks = propHooks->mProtoHooks));
+
+ // aIndex was bigger than the number of constants we have.
+ return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetInfoForParam(uint16_t aIndex, const nsXPTParamInfo* aParam, nsIInterfaceInfo** aRetVal)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetIIDForParam(uint16_t aIndex, const nsXPTParamInfo* aParam, nsIID** aRetVal)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetTypeForParam(uint16_t aInex, const nsXPTParamInfo* aParam, uint16_t aDimension, nsXPTType* aRetVal)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetSizeIsArgNumberForParam(uint16_t aInex, const nsXPTParamInfo* aParam, uint16_t aDimension, uint8_t* aRetVal)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetInterfaceIsArgNumberForParam(uint16_t aInex, const nsXPTParamInfo* aParam, uint8_t* aRetVal)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::IsIID(const nsIID* aIID, bool* aRetVal)
+{
+ *aRetVal = mIID.Equals(*aIID);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetNameShared(const char** aName)
+{
+ *aName = mName.get();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::GetIIDShared(const nsIID** aIID)
+{
+ *aIID = &mIID;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::IsFunction(bool* aRetVal)
+{
+ *aRetVal = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ShimInterfaceInfo::HasAncestor(const nsIID* aIID, bool* aRetVal)
+{
+ *aRetVal = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(nsresult)
+ShimInterfaceInfo::GetIIDForParamNoAlloc(uint16_t aIndex, const nsXPTParamInfo* aInfo, nsIID* aIID)
+{
+ MOZ_ASSERT(false, "This should never be called");
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/xpcom/reflect/xptinfo/ShimInterfaceInfo.h b/xpcom/reflect/xptinfo/ShimInterfaceInfo.h
new file mode 100644
index 0000000000..868f503a59
--- /dev/null
+++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef ShimInterfaceInfo_h
+#define ShimInterfaceInfo_h
+
+#include "mozilla/Attributes.h"
+#include "nsIInterfaceInfo.h"
+#include "nsString.h"
+#include "nsID.h"
+#include "nsTArray.h"
+#include "xptinfo.h"
+#include "nsAutoPtr.h"
+#include "js/RootingAPI.h"
+
+namespace mozilla {
+namespace dom {
+struct NativePropertyHooks;
+} // namespace dom
+} // namespace mozilla
+
+class ShimInterfaceInfo final : public nsIInterfaceInfo
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIINTERFACEINFO
+
+ // Construct a ShimInterfaceInfo object if we have a shim available for aName.
+ // Otherwise, returns nullptr.
+ static already_AddRefed<ShimInterfaceInfo>
+ MaybeConstruct(const char* aName, JSContext* cx);
+
+private:
+ ShimInterfaceInfo(const nsIID& aIID,
+ const char* aName,
+ const mozilla::dom::NativePropertyHooks* aNativePropHooks);
+
+ ~ShimInterfaceInfo() {}
+
+private:
+ nsIID mIID;
+ nsAutoCString mName;
+ const mozilla::dom::NativePropertyHooks* mNativePropHooks;
+};
+
+#endif
diff --git a/xpcom/reflect/xptinfo/TODO b/xpcom/reflect/xptinfo/TODO
new file mode 100644
index 0000000000..50215a4fb8
--- /dev/null
+++ b/xpcom/reflect/xptinfo/TODO
@@ -0,0 +1,20 @@
+/* jband - 03/24/00 - */
+
+- DOCS
+- improve error handling
+ - should some errors really be warnings?
+ - should autoreg support additional channel to receive warnings so that
+ an installer can decide whether or not to accept the consequences of
+ leaving the newly installed files in place?
+- verification of interfaces (warnings and/or errors)
+ - verify that repeated interfaces are identical in all ways
+ - verify that interface names are always one-to-one with iids
+- check for truncated xpt files and version problems
+ - http://bugzilla.mozilla.org/show_bug.cgi?id=33193
+- TESTS!
+ - e.g. verify the merge stuff really works for various inputs.
+ - we really need a set of .xpt and .zip files and code that does an array
+ of autoreg and interfaceinof use activitities to test various corners
+ of the system.
+- better autoreg logging
+- use only 32 bits for file size?
diff --git a/xpcom/reflect/xptinfo/XPTInterfaceInfoManager.h b/xpcom/reflect/xptinfo/XPTInterfaceInfoManager.h
new file mode 100644
index 0000000000..e72153ad21
--- /dev/null
+++ b/xpcom/reflect/xptinfo/XPTInterfaceInfoManager.h
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_XPTInterfaceInfoManager_h_
+#define mozilla_XPTInterfaceInfoManager_h_
+
+#include "nsIInterfaceInfoManager.h"
+#include "nsIMemoryReporter.h"
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/ReentrantMonitor.h"
+#include "nsDataHashtable.h"
+
+template<typename T> class nsCOMArray;
+class nsIMemoryReporter;
+struct XPTHeader;
+struct XPTInterfaceDirectoryEntry;
+class xptiInterfaceEntry;
+class xptiInterfaceInfo;
+class xptiTypelibGuts;
+
+namespace mozilla {
+
+class XPTInterfaceInfoManager final
+ : public nsIInterfaceInfoManager
+ , public nsIMemoryReporter
+{
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIINTERFACEINFOMANAGER
+ NS_DECL_NSIMEMORYREPORTER
+
+public:
+ // GetSingleton() is infallible
+ static XPTInterfaceInfoManager* GetSingleton();
+ static void FreeInterfaceInfoManager();
+
+ void GetScriptableInterfaces(nsCOMArray<nsIInterfaceInfo>& aInterfaces);
+
+ void RegisterBuffer(char *buf, uint32_t length);
+
+ static Mutex& GetResolveLock()
+ {
+ return GetSingleton()->mResolveLock;
+ }
+
+ xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+
+private:
+ XPTInterfaceInfoManager();
+ ~XPTInterfaceInfoManager();
+
+ void InitMemoryReporter();
+
+ void RegisterXPTHeader(XPTHeader* aHeader);
+
+ // idx is the index of this interface in the XPTHeader
+ void VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
+ uint16_t idx,
+ xptiTypelibGuts* typelib);
+
+private:
+
+ class xptiWorkingSet
+ {
+ public:
+ xptiWorkingSet();
+ ~xptiWorkingSet();
+
+ bool IsValid() const;
+
+ void InvalidateInterfaceInfos();
+ void ClearHashTables();
+
+ // utility methods...
+
+ enum {NOT_FOUND = 0xffffffff};
+
+ // Directory stuff...
+
+ uint32_t GetDirectoryCount();
+ nsresult GetCloneOfDirectoryAt(uint32_t i, nsIFile** dir);
+ nsresult GetDirectoryAt(uint32_t i, nsIFile** dir);
+ bool FindDirectory(nsIFile* dir, uint32_t* index);
+ bool FindDirectoryOfFile(nsIFile* file, uint32_t* index);
+ bool DirectoryAtMatchesPersistentDescriptor(uint32_t i, const char* desc);
+
+ private:
+ uint32_t mFileCount;
+ uint32_t mMaxFileCount;
+
+ public:
+ // XXX make these private with accessors
+ // mTableMonitor must be held across:
+ // * any read from or write to mIIDTable or mNameTable
+ // * any writing to the links between an xptiInterfaceEntry
+ // and its xptiInterfaceInfo (mEntry/mInfo)
+ mozilla::ReentrantMonitor mTableReentrantMonitor;
+ nsDataHashtable<nsIDHashKey, xptiInterfaceEntry*> mIIDTable;
+ nsDataHashtable<nsDepCharHashKey, xptiInterfaceEntry*> mNameTable;
+ };
+
+ // XXX xptiInterfaceInfo want's to poke at the working set itself
+ friend class ::xptiInterfaceInfo;
+ friend class ::xptiInterfaceEntry;
+ friend class ::xptiTypelibGuts;
+
+ xptiWorkingSet mWorkingSet;
+ Mutex mResolveLock;
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/xpcom/reflect/xptinfo/moz.build b/xpcom/reflect/xptinfo/moz.build
new file mode 100644
index 0000000000..3209497829
--- /dev/null
+++ b/xpcom/reflect/xptinfo/moz.build
@@ -0,0 +1,37 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ 'ShimInterfaceInfo.cpp',
+ 'xptiInterfaceInfo.cpp',
+ 'xptiInterfaceInfoManager.cpp',
+ 'xptiTypelibGuts.cpp',
+ 'xptiWorkingSet.cpp',
+]
+
+XPIDL_SOURCES += [
+ 'nsIInterfaceInfo.idl',
+ 'nsIInterfaceInfoManager.idl',
+]
+
+XPIDL_MODULE = 'xpcom_xpti'
+
+EXPORTS += [
+ 'xptinfo.h',
+]
+
+EXPORTS.mozilla += [
+ 'XPTInterfaceInfoManager.h',
+]
+
+LOCAL_INCLUDES += [
+ '/dom/base',
+]
+
+FINAL_LIBRARY = 'xul'
+
+if CONFIG['GNU_CXX']:
+ CXXFLAGS += ['-Wno-error=shadow']
diff --git a/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl b/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl
new file mode 100644
index 0000000000..8b902d5ee3
--- /dev/null
+++ b/xpcom/reflect/xptinfo/nsIInterfaceInfo.idl
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* The nsIInterfaceInfo public declaration. */
+
+
+#include "nsISupports.idl"
+
+// forward declaration of non-XPCOM types
+
+[ptr] native nsXPTMethodInfoPtr(nsXPTMethodInfo);
+[ptr] native nsXPTParamInfoPtr(nsXPTParamInfo);
+ native nsXPTType(nsXPTType);
+
+// We bend the rules to do a [shared] nsIID (but this is never scriptable)
+[ptr] native nsIIDPtrShared(nsIID);
+
+%{C++
+class nsXPTMethodInfo;
+class nsXPTParamInfo;
+class nsXPTType;
+%}
+
+[builtinclass, uuid(3820e663-8e22-4789-b470-56bcf7083f2b)]
+interface nsIInterfaceInfo : nsISupports
+{
+ readonly attribute string name;
+ readonly attribute nsIIDPtr InterfaceIID;
+
+ boolean isScriptable();
+ boolean isBuiltinClass();
+
+ readonly attribute nsIInterfaceInfo parent;
+
+ /**
+ * These include counts for parent (and all ancestors).
+ */
+ readonly attribute uint16_t methodCount;
+ readonly attribute uint16_t constantCount;
+
+ /**
+ * These include methods and constants for parent (and all ancestors).
+ *
+ * These do *not* make copies ***explicit bending of XPCOM rules***.
+ */
+
+ void getMethodInfo(in uint16_t index,
+ [shared, retval] out nsXPTMethodInfoPtr info);
+
+ void getMethodInfoForName(in string methodName, out uint16_t index,
+ [shared, retval] out nsXPTMethodInfoPtr info);
+
+ void getConstant(in uint16_t index,
+ out jsval constant,
+ out string name);
+
+
+ /**
+ * Get the interface information or iid associated with a param of some
+ * method in this interface.
+ */
+
+ nsIInterfaceInfo getInfoForParam(in uint16_t methodIndex,
+ [const] in nsXPTParamInfoPtr param);
+
+ nsIIDPtr getIIDForParam(in uint16_t methodIndex,
+ [const] in nsXPTParamInfoPtr param);
+
+
+ /**
+ * These do *not* make copies ***explicit bending of XPCOM rules***.
+ */
+
+ nsXPTType getTypeForParam(in uint16_t methodIndex,
+ [const] in nsXPTParamInfoPtr param,
+ in uint16_t dimension);
+
+ uint8_t getSizeIsArgNumberForParam(in uint16_t methodIndex,
+ [const] in nsXPTParamInfoPtr param,
+ in uint16_t dimension);
+
+ uint8_t getInterfaceIsArgNumberForParam(in uint16_t methodIndex,
+ [const] in nsXPTParamInfoPtr param);
+
+ boolean isIID(in nsIIDPtr IID);
+
+ void getNameShared([shared,retval] out string name);
+ void getIIDShared([shared,retval] out nsIIDPtrShared iid);
+
+ boolean isFunction();
+
+ boolean hasAncestor(in nsIIDPtr iid);
+
+ [notxpcom] nsresult getIIDForParamNoAlloc(in uint16_t methodIndex,
+ [const] in nsXPTParamInfoPtr param,
+ out nsIID iid);
+
+ boolean isMainProcessScriptableOnly();
+};
diff --git a/xpcom/reflect/xptinfo/nsIInterfaceInfoManager.idl b/xpcom/reflect/xptinfo/nsIInterfaceInfoManager.idl
new file mode 100644
index 0000000000..bc63aed493
--- /dev/null
+++ b/xpcom/reflect/xptinfo/nsIInterfaceInfoManager.idl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* The nsIInterfaceInfoManager public declaration. */
+
+
+#include "nsISupports.idl"
+
+interface nsIInterfaceInfo;
+
+[builtinclass, uuid(1d53d8d9-1d92-428f-b5cc-198b55e897d7)]
+interface nsIInterfaceInfoManager : nsISupports
+{
+ nsIInterfaceInfo getInfoForIID(in nsIIDPtr iid);
+ nsIInterfaceInfo getInfoForName(in string name);
+};
+
+%{C++
+#define NS_INTERFACEINFOMANAGER_SERVICE_CID \
+ { /* 13bef784-f8e0-4f96-85c1-09f9ef4f9a19 */ \
+ 0x13bef784, 0xf8e0, 0x4f96, \
+ {0x85, 0xc1, 0x09, 0xf9, 0xef, 0x4f, 0x9a, 0x19} }
+
+#define NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID \
+ "@mozilla.org/xpti/interfaceinfomanager-service;1"
+%}
diff --git a/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp b/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
new file mode 100644
index 0000000000..8ea80fda14
--- /dev/null
+++ b/xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp
@@ -0,0 +1,742 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */
+
+#include "xptiprivate.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/XPTInterfaceInfoManager.h"
+#include "mozilla/PodOperations.h"
+#include "jsapi.h"
+
+using namespace mozilla;
+
+/* static */ xptiInterfaceEntry*
+xptiInterfaceEntry::Create(const char* name, const nsID& iid,
+ XPTInterfaceDescriptor* aDescriptor,
+ xptiTypelibGuts* aTypelib)
+{
+ int namelen = strlen(name);
+ void* place =
+ XPT_CALLOC8(gXPTIStructArena, sizeof(xptiInterfaceEntry) + namelen);
+ if (!place) {
+ return nullptr;
+ }
+ return new (place) xptiInterfaceEntry(name, namelen, iid, aDescriptor,
+ aTypelib);
+}
+
+xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
+ size_t nameLength,
+ const nsID& iid,
+ XPTInterfaceDescriptor* aDescriptor,
+ xptiTypelibGuts* aTypelib)
+ : mIID(iid)
+ , mDescriptor(aDescriptor)
+ , mTypelib(aTypelib)
+ , mParent(nullptr)
+ , mInfo(nullptr)
+ , mMethodBaseIndex(0)
+ , mConstantBaseIndex(0)
+ , mFlags(0)
+{
+ memcpy(mName, name, nameLength);
+ SetResolvedState(PARTIALLY_RESOLVED);
+}
+
+bool
+xptiInterfaceEntry::Resolve()
+{
+ MutexAutoLock lock(XPTInterfaceInfoManager::GetResolveLock());
+ return ResolveLocked();
+}
+
+bool
+xptiInterfaceEntry::ResolveLocked()
+{
+ int resolvedState = GetResolveState();
+
+ if(resolvedState == FULLY_RESOLVED)
+ return true;
+ if(resolvedState == RESOLVE_FAILED)
+ return false;
+
+ NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!");
+
+ // Finish out resolution by finding parent and Resolving it so
+ // we can set the info we get from it.
+
+ uint16_t parent_index = mDescriptor->parent_interface;
+
+ if(parent_index)
+ {
+ xptiInterfaceEntry* parent =
+ mTypelib->GetEntryAt(parent_index - 1);
+
+ if(!parent || !parent->EnsureResolvedLocked())
+ {
+ SetResolvedState(RESOLVE_FAILED);
+ return false;
+ }
+
+ mParent = parent;
+ if (parent->GetHasNotXPCOMFlag()) {
+ SetHasNotXPCOMFlag();
+ } else {
+ for (uint16_t idx = 0; idx < mDescriptor->num_methods; ++idx) {
+ nsXPTMethodInfo* method = reinterpret_cast<nsXPTMethodInfo*>(
+ mDescriptor->method_descriptors + idx);
+ if (method->IsNotXPCOM()) {
+ SetHasNotXPCOMFlag();
+ break;
+ }
+ }
+ }
+
+
+ mMethodBaseIndex =
+ parent->mMethodBaseIndex +
+ parent->mDescriptor->num_methods;
+
+ mConstantBaseIndex =
+ parent->mConstantBaseIndex +
+ parent->mDescriptor->num_constants;
+
+ }
+ LOG_RESOLVE(("+ complete resolve of %s\n", mName));
+
+ SetResolvedState(FULLY_RESOLVED);
+ return true;
+}
+
+/**************************************************/
+// These non-virtual methods handle the delegated nsIInterfaceInfo methods.
+
+nsresult
+xptiInterfaceEntry::GetName(char **name)
+{
+ // It is not necessary to Resolve because this info is read from manifest.
+ *name = (char*) nsMemory::Clone(mName, strlen(mName)+1);
+ return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+nsresult
+xptiInterfaceEntry::GetIID(nsIID **iid)
+{
+ // It is not necessary to Resolve because this info is read from manifest.
+ *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID));
+ return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+nsresult
+xptiInterfaceEntry::IsScriptable(bool* result)
+{
+ // It is not necessary to Resolve because this info is read from manifest.
+ *result = GetScriptableFlag();
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::IsFunction(bool* result)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ *result = XPT_ID_IS_FUNCTION(mDescriptor->flags);
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetMethodCount(uint16_t* count)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ *count = mMethodBaseIndex +
+ mDescriptor->num_methods;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetConstantCount(uint16_t* count)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(!count)
+ return NS_ERROR_UNEXPECTED;
+
+ *count = mConstantBaseIndex +
+ mDescriptor->num_constants;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetMethodInfo(uint16_t index, const nsXPTMethodInfo** info)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(index < mMethodBaseIndex)
+ return mParent->GetMethodInfo(index, info);
+
+ if(index >= mMethodBaseIndex +
+ mDescriptor->num_methods)
+ {
+ NS_ERROR("bad param");
+ *info = nullptr;
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // else...
+ *info = reinterpret_cast<nsXPTMethodInfo*>
+ (&mDescriptor->method_descriptors[index - mMethodBaseIndex]);
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16_t *index,
+ const nsXPTMethodInfo** result)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ // This is a slow algorithm, but this is not expected to be called much.
+ for(uint16_t i = 0; i < mDescriptor->num_methods; ++i)
+ {
+ const nsXPTMethodInfo* info;
+ info = reinterpret_cast<nsXPTMethodInfo*>
+ (&mDescriptor->
+ method_descriptors[i]);
+ if (PL_strcmp(methodName, info->GetName()) == 0) {
+ *index = i + mMethodBaseIndex;
+ *result = info;
+ return NS_OK;
+ }
+ }
+
+ if(mParent)
+ return mParent->GetMethodInfoForName(methodName, index, result);
+ else
+ {
+ *index = 0;
+ *result = 0;
+ return NS_ERROR_INVALID_ARG;
+ }
+}
+
+nsresult
+xptiInterfaceEntry::GetConstant(uint16_t index, JS::MutableHandleValue constant,
+ char** name)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(index < mConstantBaseIndex)
+ return mParent->GetConstant(index, constant, name);
+
+ if(index >= mConstantBaseIndex +
+ mDescriptor->num_constants)
+ {
+ NS_PRECONDITION(0, "bad param");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const auto& c = mDescriptor->const_descriptors[index - mConstantBaseIndex];
+ AutoJSContext cx;
+ JS::Rooted<JS::Value> v(cx);
+ v.setUndefined();
+
+ switch (c.type.prefix.flags) {
+ case nsXPTType::T_I8:
+ {
+ v.setInt32(c.value.i8);
+ break;
+ }
+ case nsXPTType::T_U8:
+ {
+ v.setInt32(c.value.ui8);
+ break;
+ }
+ case nsXPTType::T_I16:
+ {
+ v.setInt32(c.value.i16);
+ break;
+ }
+ case nsXPTType::T_U16:
+ {
+ v.setInt32(c.value.ui16);
+ break;
+ }
+ case nsXPTType::T_I32:
+ {
+ v = JS_NumberValue(c.value.i32);
+ break;
+ }
+ case nsXPTType::T_U32:
+ {
+ v = JS_NumberValue(c.value.ui32);
+ break;
+ }
+ default:
+ {
+#ifdef DEBUG
+ NS_ERROR("Non-numeric constant found in interface.");
+#endif
+ }
+ }
+
+ constant.set(v);
+ *name = ToNewCString(nsDependentCString(c.name));
+
+ return NS_OK;
+}
+
+// this is a private helper
+
+nsresult
+xptiInterfaceEntry::GetInterfaceIndexForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param,
+ uint16_t* interfaceIndex)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(methodIndex < mMethodBaseIndex)
+ return mParent->GetInterfaceIndexForParam(methodIndex, param,
+ interfaceIndex);
+
+ if(methodIndex >= mMethodBaseIndex +
+ mDescriptor->num_methods)
+ {
+ NS_ERROR("bad param");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const XPTTypeDescriptor *td = &param->type;
+
+ while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
+ td = &mDescriptor->additional_types[td->u.array.additional_type];
+ }
+
+ if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) {
+ NS_ERROR("not an interface");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ *interfaceIndex = (td->u.iface.iface_hi8 << 8) | td->u.iface.iface_lo8;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetEntryForParam(uint16_t methodIndex,
+ const nsXPTParamInfo * param,
+ xptiInterfaceEntry** entry)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(methodIndex < mMethodBaseIndex)
+ return mParent->GetEntryForParam(methodIndex, param, entry);
+
+ uint16_t interfaceIndex = 0;
+ nsresult rv = GetInterfaceIndexForParam(methodIndex, param,
+ &interfaceIndex);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ xptiInterfaceEntry* theEntry = mTypelib->GetEntryAt(interfaceIndex - 1);
+
+ // This can happen if a declared interface is not available at runtime.
+ if(!theEntry)
+ {
+ *entry = nullptr;
+ return NS_ERROR_FAILURE;
+ }
+
+ *entry = theEntry;
+ return NS_OK;
+}
+
+already_AddRefed<ShimInterfaceInfo>
+xptiInterfaceEntry::GetShimForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param)
+{
+ if(methodIndex < mMethodBaseIndex) {
+ return mParent->GetShimForParam(methodIndex, param);
+ }
+
+ uint16_t interfaceIndex = 0;
+ nsresult rv = GetInterfaceIndexForParam(methodIndex, param,
+ &interfaceIndex);
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+
+ const char* shimName = mTypelib->GetEntryNameAt(interfaceIndex - 1);
+ RefPtr<ShimInterfaceInfo> shim =
+ ShimInterfaceInfo::MaybeConstruct(shimName, nullptr);
+ return shim.forget();
+}
+
+nsresult
+xptiInterfaceEntry::GetInfoForParam(uint16_t methodIndex,
+ const nsXPTParamInfo *param,
+ nsIInterfaceInfo** info)
+{
+ xptiInterfaceEntry* entry;
+ nsresult rv = GetEntryForParam(methodIndex, param, &entry);
+ if (NS_FAILED(rv)) {
+ RefPtr<ShimInterfaceInfo> shim = GetShimForParam(methodIndex, param);
+ if (!shim) {
+ return rv;
+ }
+
+ shim.forget(info);
+ return NS_OK;
+ }
+
+ *info = entry->InterfaceInfo().take();
+
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetIIDForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param, nsIID** iid)
+{
+ xptiInterfaceEntry* entry;
+ nsresult rv = GetEntryForParam(methodIndex, param, &entry);
+ if (NS_FAILED(rv)) {
+ RefPtr<ShimInterfaceInfo> shim = GetShimForParam(methodIndex, param);
+ if (!shim) {
+ return rv;
+ }
+
+ return shim->GetInterfaceIID(iid);
+ }
+ return entry->GetIID(iid);
+}
+
+nsresult
+xptiInterfaceEntry::GetIIDForParamNoAlloc(uint16_t methodIndex,
+ const nsXPTParamInfo * param,
+ nsIID *iid)
+{
+ xptiInterfaceEntry* entry;
+ nsresult rv = GetEntryForParam(methodIndex, param, &entry);
+ if (NS_FAILED(rv)) {
+ RefPtr<ShimInterfaceInfo> shim = GetShimForParam(methodIndex, param);
+ if (!shim) {
+ return rv;
+ }
+
+ const nsIID* shimIID;
+ DebugOnly<nsresult> rv2 = shim->GetIIDShared(&shimIID);
+ MOZ_ASSERT(NS_SUCCEEDED(rv2));
+ *iid = *shimIID;
+ return NS_OK;
+ }
+ *iid = entry->mIID;
+ return NS_OK;
+}
+
+// this is a private helper
+nsresult
+xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
+ uint16_t dimension,
+ const XPTTypeDescriptor** type)
+{
+ NS_ASSERTION(IsFullyResolved(), "bad state");
+
+ const XPTTypeDescriptor *td = &param->type;
+ const XPTTypeDescriptor *additional_types =
+ mDescriptor->additional_types;
+
+ for (uint16_t i = 0; i < dimension; i++) {
+ if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) {
+ NS_ERROR("bad dimension");
+ return NS_ERROR_INVALID_ARG;
+ }
+ td = &additional_types[td->u.array.additional_type];
+ }
+
+ *type = td;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetTypeForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param,
+ uint16_t dimension,
+ nsXPTType* type)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(methodIndex < mMethodBaseIndex)
+ return mParent->
+ GetTypeForParam(methodIndex, param, dimension, type);
+
+ if(methodIndex >= mMethodBaseIndex +
+ mDescriptor->num_methods)
+ {
+ NS_ERROR("bad index");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const XPTTypeDescriptor *td;
+
+ if(dimension) {
+ nsresult rv = GetTypeInArray(param, dimension, &td);
+ if(NS_FAILED(rv))
+ return rv;
+ }
+ else
+ td = &param->type;
+
+ *type = nsXPTType(td->prefix);
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param,
+ uint16_t dimension,
+ uint8_t* argnum)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(methodIndex < mMethodBaseIndex)
+ return mParent->
+ GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum);
+
+ if(methodIndex >= mMethodBaseIndex +
+ mDescriptor->num_methods)
+ {
+ NS_ERROR("bad index");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const XPTTypeDescriptor *td;
+
+ if(dimension) {
+ nsresult rv = GetTypeInArray(param, dimension, &td);
+ if(NS_FAILED(rv))
+ return rv;
+ }
+ else
+ td = &param->type;
+
+ // verify that this is a type that has size_is
+ switch (XPT_TDP_TAG(td->prefix)) {
+ case TD_ARRAY:
+ *argnum = td->u.array.argnum;
+ break;
+ case TD_PSTRING_SIZE_IS:
+ case TD_PWSTRING_SIZE_IS:
+ *argnum = td->u.pstring_is.argnum;
+ break;
+ default:
+ NS_ERROR("not a size_is");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param,
+ uint8_t* argnum)
+{
+ if(!EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+
+ if(methodIndex < mMethodBaseIndex)
+ return mParent->
+ GetInterfaceIsArgNumberForParam(methodIndex, param, argnum);
+
+ if(methodIndex >= mMethodBaseIndex +
+ mDescriptor->num_methods)
+ {
+ NS_ERROR("bad index");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const XPTTypeDescriptor *td = &param->type;
+
+ while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
+ td = &mDescriptor->additional_types[td->u.array.additional_type];
+ }
+
+ if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) {
+ NS_ERROR("not an iid_is");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ *argnum = td->u.interface_is.argnum;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::IsIID(const nsIID * iid, bool *_retval)
+{
+ // It is not necessary to Resolve because this info is read from manifest.
+ *_retval = mIID.Equals(*iid);
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetNameShared(const char **name)
+{
+ // It is not necessary to Resolve because this info is read from manifest.
+ *name = mName;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::GetIIDShared(const nsIID * *iid)
+{
+ // It is not necessary to Resolve because this info is read from manifest.
+ *iid = &mIID;
+ return NS_OK;
+}
+
+nsresult
+xptiInterfaceEntry::HasAncestor(const nsIID * iid, bool *_retval)
+{
+ *_retval = false;
+
+ for(xptiInterfaceEntry* current = this;
+ current;
+ current = current->mParent)
+ {
+ if(current->mIID.Equals(*iid))
+ {
+ *_retval = true;
+ break;
+ }
+ if(!current->EnsureResolved())
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+/***************************************************/
+
+already_AddRefed<xptiInterfaceInfo>
+xptiInterfaceEntry::InterfaceInfo()
+{
+#ifdef DEBUG
+ XPTInterfaceInfoManager::GetSingleton()->mWorkingSet.mTableReentrantMonitor.
+ AssertCurrentThreadIn();
+#endif
+
+ if(!mInfo)
+ {
+ mInfo = new xptiInterfaceInfo(this);
+ }
+
+ RefPtr<xptiInterfaceInfo> info = mInfo;
+ return info.forget();
+}
+
+void
+xptiInterfaceEntry::LockedInvalidateInterfaceInfo()
+{
+ if(mInfo)
+ {
+ mInfo->Invalidate();
+ mInfo = nullptr;
+ }
+}
+
+bool
+xptiInterfaceInfo::BuildParent()
+{
+ mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::GetSingleton()->
+ mWorkingSet.mTableReentrantMonitor);
+ NS_ASSERTION(mEntry &&
+ mEntry->IsFullyResolved() &&
+ !mParent &&
+ mEntry->Parent(),
+ "bad BuildParent call");
+ mParent = mEntry->Parent()->InterfaceInfo();
+ return true;
+}
+
+/***************************************************************************/
+
+NS_IMPL_QUERY_INTERFACE(xptiInterfaceInfo, nsIInterfaceInfo)
+
+xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry)
+ : mEntry(entry)
+{
+}
+
+xptiInterfaceInfo::~xptiInterfaceInfo()
+{
+ NS_ASSERTION(!mEntry, "bad state in dtor");
+}
+
+void
+xptiInterfaceInfo::Invalidate()
+{
+ mParent = nullptr;
+ mEntry = nullptr;
+}
+
+MozExternalRefCountType
+xptiInterfaceInfo::AddRef(void)
+{
+ nsrefcnt cnt = ++mRefCnt;
+ NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this));
+ return cnt;
+}
+
+MozExternalRefCountType
+xptiInterfaceInfo::Release(void)
+{
+ xptiInterfaceEntry* entry = mEntry;
+ nsrefcnt cnt = --mRefCnt;
+ NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo");
+ if(!cnt)
+ {
+ mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::
+ GetSingleton()->mWorkingSet.
+ mTableReentrantMonitor);
+
+ // If InterfaceInfo added and *released* a reference before we
+ // acquired the monitor then 'this' might already be dead. In that
+ // case we would not want to try to access any instance data. We
+ // would want to bail immediately. If 'this' is already dead then the
+ // entry will no longer have a pointer to 'this'. So, we can protect
+ // ourselves from danger without more aggressive locking.
+ if(entry && !entry->InterfaceInfoEquals(this))
+ return 0;
+
+ // If InterfaceInfo added a reference before we acquired the monitor
+ // then we want to bail out of here without destorying the object.
+ if(mRefCnt)
+ return 1;
+
+ if(mEntry)
+ {
+ mEntry->LockedInterfaceInfoDeathNotification();
+ mEntry = nullptr;
+ }
+
+ delete this;
+ return 0;
+ }
+ return cnt;
+}
+
+/***************************************************************************/
diff --git a/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp b/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp
new file mode 100644
index 0000000000..600a99b94d
--- /dev/null
+++ b/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Implementation of xptiInterfaceInfoManager. */
+
+#include "mozilla/XPTInterfaceInfoManager.h"
+
+#include "mozilla/FileUtils.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/StaticPtr.h"
+
+#include "xptiprivate.h"
+#include "nsDependentString.h"
+#include "nsString.h"
+#include "nsArrayEnumerator.h"
+#include "nsDirectoryService.h"
+#include "nsIMemoryReporter.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(
+ XPTInterfaceInfoManager,
+ nsIInterfaceInfoManager,
+ nsIMemoryReporter)
+
+static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager;
+
+size_t
+XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+{
+ size_t n = aMallocSizeOf(this);
+ ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
+ // The entries themselves are allocated out of an arena accounted
+ // for elsewhere, so don't measure them
+ n += mWorkingSet.mIIDTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ n += mWorkingSet.mNameTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ return n;
+}
+
+MOZ_DEFINE_MALLOC_SIZE_OF(XPTIMallocSizeOf)
+
+NS_IMETHODIMP
+XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport,
+ nsISupports* aData, bool aAnonymize)
+{
+ size_t amount = SizeOfIncludingThis(XPTIMallocSizeOf);
+
+ // Measure gXPTIStructArena here, too. This is a bit grotty because it
+ // doesn't belong to the XPTIInterfaceInfoManager, but there's no
+ // obviously better place to measure it.
+ amount += XPT_SizeOfArenaIncludingThis(gXPTIStructArena, XPTIMallocSizeOf);
+
+ MOZ_COLLECT_REPORT(
+ "explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount,
+ "Memory used by the XPCOM typelib system.");
+
+ return NS_OK;
+}
+
+// static
+XPTInterfaceInfoManager*
+XPTInterfaceInfoManager::GetSingleton()
+{
+ if (!gInterfaceInfoManager) {
+ gInterfaceInfoManager = new XPTInterfaceInfoManager();
+ gInterfaceInfoManager->InitMemoryReporter();
+ }
+ return gInterfaceInfoManager;
+}
+
+void
+XPTInterfaceInfoManager::FreeInterfaceInfoManager()
+{
+ gInterfaceInfoManager = nullptr;
+}
+
+XPTInterfaceInfoManager::XPTInterfaceInfoManager()
+ : mWorkingSet(),
+ mResolveLock("XPTInterfaceInfoManager.mResolveLock")
+{
+}
+
+XPTInterfaceInfoManager::~XPTInterfaceInfoManager()
+{
+ // We only do this on shutdown of the service.
+ mWorkingSet.InvalidateInterfaceInfos();
+
+ UnregisterWeakMemoryReporter(this);
+}
+
+void
+XPTInterfaceInfoManager::InitMemoryReporter()
+{
+ RegisterWeakMemoryReporter(this);
+}
+
+void
+XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length)
+{
+ XPTState state;
+ XPT_InitXDRState(&state, buf, length);
+
+ XPTCursor curs;
+ NotNull<XPTCursor*> cursor = WrapNotNull(&curs);
+ if (!XPT_MakeCursor(&state, XPT_HEADER, 0, cursor)) {
+ return;
+ }
+
+ XPTHeader *header = nullptr;
+ if (XPT_DoHeader(gXPTIStructArena, cursor, &header)) {
+ RegisterXPTHeader(header);
+ }
+}
+
+void
+XPTInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader)
+{
+ if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) {
+ NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt");
+ LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION));
+ }
+
+ xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader);
+
+ ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
+ for(uint16_t k = 0; k < aHeader->num_interfaces; k++)
+ VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib);
+}
+
+void
+XPTInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
+ uint16_t idx,
+ xptiTypelibGuts* typelib)
+{
+ if (!iface->interface_descriptor)
+ return;
+
+ // The number of maximum methods is not arbitrary. It is the same value as
+ // in xpcom/reflect/xptcall/genstubs.pl; do not change this value
+ // without changing that one or you WILL see problems.
+ if (iface->interface_descriptor->num_methods > 250 &&
+ !(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags))) {
+ NS_ASSERTION(0, "Too many methods to handle for the stub, cannot load");
+ fprintf(stderr, "ignoring too large interface: %s\n", iface->name);
+ return;
+ }
+
+ mWorkingSet.mTableReentrantMonitor.AssertCurrentThreadIn();
+ xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid);
+ if (entry) {
+ // XXX validate this info to find possible inconsistencies
+ LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name));
+ return;
+ }
+
+ // Build a new xptiInterfaceEntry object and hook it up.
+
+ entry = xptiInterfaceEntry::Create(iface->name,
+ iface->iid,
+ iface->interface_descriptor,
+ typelib);
+ if (!entry)
+ return;
+
+ //XXX We should SetHeader too as part of the validation, no?
+ entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
+ entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags));
+ entry->SetMainProcessScriptableOnlyFlag(
+ XPT_ID_IS_MAIN_PROCESS_SCRIPTABLE_ONLY(iface->interface_descriptor->flags));
+
+ mWorkingSet.mIIDTable.Put(entry->IID(), entry);
+ mWorkingSet.mNameTable.Put(entry->GetTheName(), entry);
+
+ typelib->SetEntryAt(idx, entry);
+
+ LOG_AUTOREG((" added interface: %s\n", iface->name));
+}
+
+// this is a private helper
+static nsresult
+EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval)
+{
+ if (!entry) {
+ *_retval = nullptr;
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<xptiInterfaceInfo> info = entry->InterfaceInfo();
+ info.forget(_retval);
+ return NS_OK;
+}
+
+xptiInterfaceEntry*
+XPTInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid)
+{
+ ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
+ return mWorkingSet.mIIDTable.Get(*iid);
+}
+
+NS_IMETHODIMP
+XPTInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval)
+{
+ NS_ASSERTION(iid, "bad param");
+ NS_ASSERTION(_retval, "bad param");
+
+ ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
+ xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
+ return EntryToInfo(entry, _retval);
+}
+
+NS_IMETHODIMP
+XPTInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval)
+{
+ NS_ASSERTION(name, "bad param");
+ NS_ASSERTION(_retval, "bad param");
+
+ ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
+ xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
+ return EntryToInfo(entry, _retval);
+}
+
+void
+XPTInterfaceInfoManager::GetScriptableInterfaces(nsCOMArray<nsIInterfaceInfo>& aInterfaces)
+{
+ // I didn't want to incur the size overhead of using nsHashtable just to
+ // make building an enumerator easier. So, this code makes a snapshot of
+ // the table using an nsCOMArray and builds an enumerator for that.
+ // We can afford this transient cost.
+
+ ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
+ aInterfaces.SetCapacity(mWorkingSet.mNameTable.Count());
+ for (auto iter = mWorkingSet.mNameTable.Iter(); !iter.Done(); iter.Next()) {
+ xptiInterfaceEntry* entry = iter.UserData();
+ if (entry->GetScriptableFlag()) {
+ nsCOMPtr<nsIInterfaceInfo> ii = entry->InterfaceInfo();
+ aInterfaces.AppendElement(ii);
+ }
+ }
+}
diff --git a/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp b/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp
new file mode 100644
index 0000000000..e2965d0b13
--- /dev/null
+++ b/xpcom/reflect/xptinfo/xptiTypelibGuts.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Implementation of xptiTypelibGuts. */
+
+#include "xptiprivate.h"
+#include "mozilla/XPTInterfaceInfoManager.h"
+
+using namespace mozilla;
+
+// Ensure through static analysis that xptiTypelibGuts won't have a vtable.
+template <class T>
+class MOZ_NEEDS_NO_VTABLE_TYPE CheckNoVTable
+{
+};
+CheckNoVTable<xptiTypelibGuts> gChecker;
+
+// static
+xptiTypelibGuts*
+xptiTypelibGuts::Create(XPTHeader* aHeader)
+{
+ NS_ASSERTION(aHeader, "bad param");
+ size_t n = sizeof(xptiTypelibGuts) +
+ sizeof(xptiInterfaceEntry*) * (aHeader->num_interfaces - 1);
+ void* place = XPT_CALLOC8(gXPTIStructArena, n);
+ if (!place)
+ return nullptr;
+ return new(place) xptiTypelibGuts(aHeader);
+}
+
+xptiInterfaceEntry*
+xptiTypelibGuts::GetEntryAt(uint16_t i)
+{
+ static const nsID zeroIID =
+ { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
+
+ NS_ASSERTION(mHeader, "bad state");
+ NS_ASSERTION(i < GetEntryCount(), "bad index");
+
+ xptiInterfaceEntry* r = mEntryArray[i];
+ if (r)
+ return r;
+
+ XPTInterfaceDirectoryEntry* iface = mHeader->interface_directory + i;
+
+ XPTInterfaceInfoManager::xptiWorkingSet& set =
+ XPTInterfaceInfoManager::GetSingleton()->mWorkingSet;
+
+ {
+ ReentrantMonitorAutoEnter monitor(set.mTableReentrantMonitor);
+ if (iface->iid.Equals(zeroIID))
+ r = set.mNameTable.Get(iface->name);
+ else
+ r = set.mIIDTable.Get(iface->iid);
+ }
+
+ if (r)
+ SetEntryAt(i, r);
+
+ return r;
+}
+
+const char*
+xptiTypelibGuts::GetEntryNameAt(uint16_t i)
+{
+ NS_ASSERTION(mHeader, "bad state");
+ NS_ASSERTION(i < GetEntryCount(), "bad index");
+
+ XPTInterfaceDirectoryEntry* iface = mHeader->interface_directory + i;
+
+ return iface->name;
+}
diff --git a/xpcom/reflect/xptinfo/xptiWorkingSet.cpp b/xpcom/reflect/xptinfo/xptiWorkingSet.cpp
new file mode 100644
index 0000000000..10f81a4b2b
--- /dev/null
+++ b/xpcom/reflect/xptinfo/xptiWorkingSet.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Implementation of xptiWorkingSet. */
+
+#include "mozilla/XPTInterfaceInfoManager.h"
+
+#include "xptiprivate.h"
+#include "nsString.h"
+
+using namespace mozilla;
+
+static const size_t XPTI_ARENA8_BLOCK_SIZE = 16 * 1024;
+static const size_t XPTI_ARENA1_BLOCK_SIZE = 8 * 1024;
+
+static const uint32_t XPTI_HASHTABLE_LENGTH = 1024;
+
+XPTInterfaceInfoManager::xptiWorkingSet::xptiWorkingSet()
+ : mTableReentrantMonitor("xptiWorkingSet::mTableReentrantMonitor")
+ , mIIDTable(XPTI_HASHTABLE_LENGTH)
+ , mNameTable(XPTI_HASHTABLE_LENGTH)
+{
+ MOZ_COUNT_CTOR(xptiWorkingSet);
+
+ gXPTIStructArena = XPT_NewArena(XPTI_ARENA8_BLOCK_SIZE,
+ XPTI_ARENA1_BLOCK_SIZE);
+}
+
+void
+XPTInterfaceInfoManager::xptiWorkingSet::InvalidateInterfaceInfos()
+{
+ ReentrantMonitorAutoEnter monitor(mTableReentrantMonitor);
+ for (auto iter = mNameTable.Iter(); !iter.Done(); iter.Next()) {
+ xptiInterfaceEntry* entry = iter.UserData();
+ entry->LockedInvalidateInterfaceInfo();
+ }
+}
+
+XPTInterfaceInfoManager::xptiWorkingSet::~xptiWorkingSet()
+{
+ MOZ_COUNT_DTOR(xptiWorkingSet);
+
+ // Only destroy the arena if we're doing leak stats. Why waste shutdown
+ // time touching pages if we don't have to?
+#ifdef NS_FREE_PERMANENT_DATA
+ XPT_DestroyArena(gXPTIStructArena);
+#endif
+}
+
+XPTArena* gXPTIStructArena;
diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h
new file mode 100644
index 0000000000..1207a42bb5
--- /dev/null
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* XPTI_PUBLIC_API and XPTI_GetInterfaceInfoManager declarations. */
+
+#ifndef xptiinfo_h___
+#define xptiinfo_h___
+
+#include "nscore.h"
+#include "xpt_struct.h"
+
+// Flyweight wrapper classes for xpt_struct.h structs.
+// Everything here is dependent upon - and sensitive to changes in -
+// xpcom/typelib/xpt/xpt_struct.h!
+
+class nsXPTType : public XPTTypeDescriptorPrefix
+{
+// NO DATA - this a flyweight wrapper
+public:
+ nsXPTType()
+ {} // random contents
+ MOZ_IMPLICIT nsXPTType(const XPTTypeDescriptorPrefix& prefix)
+ {*(XPTTypeDescriptorPrefix*)this = prefix;}
+
+ MOZ_IMPLICIT nsXPTType(const uint8_t& prefix)
+ {*(uint8_t*)this = prefix;}
+
+ nsXPTType& operator=(uint8_t val)
+ {flags = val; return *this;}
+
+ nsXPTType& operator=(const nsXPTType& other)
+ {flags = other.flags; return *this;}
+
+ operator uint8_t() const
+ {return flags;}
+
+ // 'Arithmetic' here roughly means that the value is self-contained and
+ // doesn't depend on anything else in memory (ie: not a pointer, not an
+ // XPCOM object, not a jsval, etc).
+ //
+ // Supposedly this terminology comes from Harbison/Steele, but it's still
+ // a rather crappy name. We'd change it if it wasn't used all over the
+ // place in xptcall. :-(
+ bool IsArithmetic() const
+ {return flags <= T_WCHAR;}
+
+ // We used to abuse 'pointer' flag bit in typelib format quite extensively.
+ // We've gotten rid of most of the cases, but there's still a fair amount
+ // of refactoring to be done in XPCWrappedJSClass before we can safely stop
+ // asking about this. In the mean time, we've got a temporary version of
+ // IsPointer() that should be equivalent to what's in the typelib.
+ bool deprecated_IsPointer() const
+ {return !IsArithmetic() && TagPart() != T_JSVAL;}
+
+ bool IsInterfacePointer() const
+ { switch (TagPart()) {
+ default:
+ return false;
+ case T_INTERFACE:
+ case T_INTERFACE_IS:
+ return true;
+ }
+ }
+
+ bool IsArray() const
+ {return TagPart() == T_ARRAY;}
+
+ // 'Dependent' means that params of this type are dependent upon other
+ // params. e.g. an T_INTERFACE_IS is dependent upon some other param at
+ // runtime to say what the interface type of this param really is.
+ bool IsDependent() const
+ { switch (TagPart()) {
+ default:
+ return false;
+ case T_INTERFACE_IS:
+ case TD_ARRAY:
+ case T_PSTRING_SIZE_IS:
+ case T_PWSTRING_SIZE_IS:
+ return true;
+ }
+ }
+
+ uint8_t TagPart() const
+ {return (uint8_t) (flags & XPT_TDP_TAGMASK);}
+
+ enum
+ {
+ T_I8 = TD_INT8 ,
+ T_I16 = TD_INT16 ,
+ T_I32 = TD_INT32 ,
+ T_I64 = TD_INT64 ,
+ T_U8 = TD_UINT8 ,
+ T_U16 = TD_UINT16 ,
+ T_U32 = TD_UINT32 ,
+ T_U64 = TD_UINT64 ,
+ T_FLOAT = TD_FLOAT ,
+ T_DOUBLE = TD_DOUBLE ,
+ T_BOOL = TD_BOOL ,
+ T_CHAR = TD_CHAR ,
+ T_WCHAR = TD_WCHAR ,
+ T_VOID = TD_VOID ,
+ T_IID = TD_PNSIID ,
+ T_DOMSTRING = TD_DOMSTRING ,
+ T_CHAR_STR = TD_PSTRING ,
+ T_WCHAR_STR = TD_PWSTRING ,
+ T_INTERFACE = TD_INTERFACE_TYPE ,
+ T_INTERFACE_IS = TD_INTERFACE_IS_TYPE,
+ T_ARRAY = TD_ARRAY ,
+ T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS ,
+ T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS ,
+ T_UTF8STRING = TD_UTF8STRING ,
+ T_CSTRING = TD_CSTRING ,
+ T_ASTRING = TD_ASTRING ,
+ T_JSVAL = TD_JSVAL
+ };
+// NO DATA - this a flyweight wrapper
+};
+
+class nsXPTParamInfo : public XPTParamDescriptor
+{
+// NO DATA - this a flyweight wrapper
+public:
+ MOZ_IMPLICIT nsXPTParamInfo(const XPTParamDescriptor& desc)
+ {*(XPTParamDescriptor*)this = desc;}
+
+
+ bool IsIn() const {return 0 != (XPT_PD_IS_IN(flags));}
+ bool IsOut() const {return 0 != (XPT_PD_IS_OUT(flags));}
+ bool IsRetval() const {return 0 != (XPT_PD_IS_RETVAL(flags));}
+ bool IsShared() const {return 0 != (XPT_PD_IS_SHARED(flags));}
+
+ // Dipper types are one of the more inscrutable aspects of xpidl. In a
+ // nutshell, dippers are empty container objects, created and passed by
+ // the caller, and filled by the callee. The callee receives a fully-
+ // formed object, and thus does not have to construct anything. But
+ // the object is functionally empty, and the callee is responsible for
+ // putting something useful inside of it.
+ //
+ // XPIDL decides which types to make dippers. The list of these types
+ // is given in the isDipperType() function in typelib.py, and is currently
+ // limited to 4 string types.
+ //
+ // When a dipper type is declared as an 'out' parameter, xpidl internally
+ // converts it to an 'in', and sets the XPT_PD_DIPPER flag on it. For this
+ // reason, dipper types are sometimes referred to as 'out parameters
+ // masquerading as in'. The burden of maintaining this illusion falls mostly
+ // on XPConnect, which creates the empty containers, and harvest the results
+ // after the call.
+ bool IsDipper() const {return 0 != (XPT_PD_IS_DIPPER(flags));}
+ bool IsOptional() const {return 0 != (XPT_PD_IS_OPTIONAL(flags));}
+ const nsXPTType GetType() const {return type.prefix;}
+
+ bool IsStringClass() const {
+ switch (GetType().TagPart()) {
+ case nsXPTType::T_ASTRING:
+ case nsXPTType::T_DOMSTRING:
+ case nsXPTType::T_UTF8STRING:
+ case nsXPTType::T_CSTRING:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // Whether this parameter is passed indirectly on the stack. This mainly
+ // applies to out/inout params, but we use it unconditionally for certain
+ // types.
+ bool IsIndirect() const {return IsOut() ||
+ GetType().TagPart() == nsXPTType::T_JSVAL;}
+
+ // NOTE: other activities on types are done via methods on nsIInterfaceInfo
+
+private:
+ nsXPTParamInfo(); // no implementation
+// NO DATA - this a flyweight wrapper
+};
+
+class nsXPTMethodInfo : public XPTMethodDescriptor
+{
+// NO DATA - this a flyweight wrapper
+public:
+ MOZ_IMPLICIT nsXPTMethodInfo(const XPTMethodDescriptor& desc)
+ {*(XPTMethodDescriptor*)this = desc;}
+
+ bool IsGetter() const {return 0 != (XPT_MD_IS_GETTER(flags) );}
+ bool IsSetter() const {return 0 != (XPT_MD_IS_SETTER(flags) );}
+ bool IsNotXPCOM() const {return 0 != (XPT_MD_IS_NOTXPCOM(flags));}
+ bool IsHidden() const {return 0 != (XPT_MD_IS_HIDDEN(flags) );}
+ bool WantsOptArgc() const {return 0 != (XPT_MD_WANTS_OPT_ARGC(flags));}
+ bool WantsContext() const {return 0 != (XPT_MD_WANTS_CONTEXT(flags));}
+ const char* GetName() const {return name;}
+ uint8_t GetParamCount() const {return num_args;}
+ /* idx was index before I got _sick_ of the warnings on Unix, sorry jband */
+ const nsXPTParamInfo GetParam(uint8_t idx) const
+ {
+ NS_PRECONDITION(idx < GetParamCount(),"bad arg");
+ return params[idx];
+ }
+ const nsXPTParamInfo GetResult() const
+ {return result;}
+private:
+ nsXPTMethodInfo(); // no implementation
+// NO DATA - this a flyweight wrapper
+};
+
+
+// forward declaration
+struct nsXPTCMiniVariant;
+
+class nsXPTConstant : public XPTConstDescriptor
+{
+// NO DATA - this a flyweight wrapper
+public:
+ MOZ_IMPLICIT nsXPTConstant(const XPTConstDescriptor& desc)
+ {*(XPTConstDescriptor*)this = desc;}
+
+ const char* GetName() const
+ {return name;}
+
+ const nsXPTType GetType() const
+ {return type.prefix;}
+
+ // XXX this is ugly. But sometimes you gotta do what you gotta do.
+ // A reinterpret_cast won't do the trick here. And this plain C cast
+ // works correctly and is safe enough.
+ // See http://bugzilla.mozilla.org/show_bug.cgi?id=49641
+ const nsXPTCMiniVariant* GetValue() const
+ {return (nsXPTCMiniVariant*) &value;}
+private:
+ nsXPTConstant(); // no implementation
+// NO DATA - this a flyweight wrapper
+};
+
+#endif /* xptiinfo_h___ */
diff --git a/xpcom/reflect/xptinfo/xptiprivate.h b/xpcom/reflect/xptinfo/xptiprivate.h
new file mode 100644
index 0000000000..c32ef9c77a
--- /dev/null
+++ b/xpcom/reflect/xptinfo/xptiprivate.h
@@ -0,0 +1,394 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Library-private header for Interface Info system. */
+
+#ifndef xptiprivate_h___
+#define xptiprivate_h___
+
+#include "nscore.h"
+#include <new>
+#include "nsISupports.h"
+
+// this after nsISupports, to pick up IID
+// so that xpt stuff doesn't try to define it itself...
+#include "xpt_struct.h"
+#include "xpt_xdr.h"
+
+#include "nsIInterfaceInfo.h"
+#include "nsIInterfaceInfoManager.h"
+#include "xptinfo.h"
+#include "ShimInterfaceInfo.h"
+
+#include "nsIServiceManager.h"
+#include "nsIFile.h"
+#include "nsIDirectoryService.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIWeakReference.h"
+
+#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/Attributes.h"
+
+#include "js/TypeDecls.h"
+
+#include "nsCRT.h"
+#include "nsMemory.h"
+
+#include "nsCOMArray.h"
+#include "nsQuickSort.h"
+
+#include "nsXPIDLString.h"
+
+#include "nsIInputStream.h"
+
+#include "nsHashKeys.h"
+#include "nsDataHashtable.h"
+#include "plstr.h"
+#include "prprf.h"
+#include "prio.h"
+#include "prtime.h"
+#include "prenv.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/***************************************************************************/
+
+#if 0 && defined(DEBUG_jband)
+#define LOG_RESOLVE(x) printf x
+#define LOG_LOAD(x) printf x
+#define LOG_AUTOREG(x) do{printf x; xptiInterfaceInfoManager::WriteToLog x;}while(0)
+#else
+#define LOG_RESOLVE(x) ((void)0)
+#define LOG_LOAD(x) ((void)0)
+#define LOG_AUTOREG(x) ((void)0)
+#endif
+
+#if 1 && defined(DEBUG_jband)
+#define SHOW_INFO_COUNT_STATS
+#endif
+
+/***************************************************************************/
+
+class xptiInterfaceInfo;
+class xptiInterfaceEntry;
+class xptiTypelibGuts;
+
+extern XPTArena* gXPTIStructArena;
+
+/***************************************************************************/
+
+/***************************************************************************/
+
+// No virtuals.
+// These are always constructed in the struct arena using placement new.
+// dtor need not be called.
+
+class xptiTypelibGuts
+{
+public:
+ static xptiTypelibGuts* Create(XPTHeader* aHeader);
+
+ XPTHeader* GetHeader() {return mHeader;}
+ uint16_t GetEntryCount() const {return mHeader->num_interfaces;}
+
+ void SetEntryAt(uint16_t i, xptiInterfaceEntry* ptr)
+ {
+ NS_ASSERTION(mHeader,"bad state!");
+ NS_ASSERTION(i < GetEntryCount(),"bad param!");
+ mEntryArray[i] = ptr;
+ }
+
+ xptiInterfaceEntry* GetEntryAt(uint16_t i);
+ const char* GetEntryNameAt(uint16_t i);
+
+private:
+ explicit xptiTypelibGuts(XPTHeader* aHeader)
+ : mHeader(aHeader)
+ { }
+ ~xptiTypelibGuts();
+
+private:
+ XPTHeader* mHeader; // hold pointer into arena
+ xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit.
+};
+
+/***************************************************************************/
+
+/***************************************************************************/
+
+// This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value
+// and a set of bitflags in one 8bit value. See below.
+
+class xptiInfoFlags
+{
+ enum {STATE_MASK = 3};
+public:
+ explicit xptiInfoFlags(uint8_t n) : mData(n) {}
+ xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {}
+
+ static uint8_t GetStateMask()
+ {return uint8_t(STATE_MASK);}
+
+ void Clear()
+ {mData = 0;}
+
+ uint8_t GetData() const
+ {return mData;}
+
+ uint8_t GetState() const
+ {return mData & GetStateMask();}
+
+ void SetState(uint8_t state)
+ {mData &= ~GetStateMask(); mData |= state;}
+
+ void SetFlagBit(uint8_t flag, bool on)
+ {if(on)
+ mData |= ~GetStateMask() & flag;
+ else
+ mData &= GetStateMask() | ~flag;}
+
+ bool GetFlagBit(uint8_t flag) const
+ {return (mData & flag) ? true : false;}
+
+private:
+ uint8_t mData;
+};
+
+/****************************************************/
+
+// No virtual methods.
+// We always create in the struct arena and construct using "placement new".
+// No members need dtor calls.
+
+class xptiInterfaceEntry
+{
+public:
+ static xptiInterfaceEntry* Create(const char* name,
+ const nsID& iid,
+ XPTInterfaceDescriptor* aDescriptor,
+ xptiTypelibGuts* aTypelib);
+
+ enum {
+ PARTIALLY_RESOLVED = 1,
+ FULLY_RESOLVED = 2,
+ RESOLVE_FAILED = 3
+ };
+
+ // Additional bit flags...
+ enum {SCRIPTABLE = 4, BUILTINCLASS = 8, HASNOTXPCOM = 16,
+ MAIN_PROCESS_SCRIPTABLE_ONLY = 32};
+
+ uint8_t GetResolveState() const {return mFlags.GetState();}
+
+ bool IsFullyResolved() const
+ {return GetResolveState() == (uint8_t) FULLY_RESOLVED;}
+
+ void SetScriptableFlag(bool on)
+ {mFlags.SetFlagBit(uint8_t(SCRIPTABLE),on);}
+ bool GetScriptableFlag() const
+ {return mFlags.GetFlagBit(uint8_t(SCRIPTABLE));}
+ void SetBuiltinClassFlag(bool on)
+ {mFlags.SetFlagBit(uint8_t(BUILTINCLASS),on);}
+ bool GetBuiltinClassFlag() const
+ {return mFlags.GetFlagBit(uint8_t(BUILTINCLASS));}
+ void SetMainProcessScriptableOnlyFlag(bool on)
+ {mFlags.SetFlagBit(uint8_t(MAIN_PROCESS_SCRIPTABLE_ONLY),on);}
+ bool GetMainProcessScriptableOnlyFlag() const
+ {return mFlags.GetFlagBit(uint8_t(MAIN_PROCESS_SCRIPTABLE_ONLY));}
+
+
+ // AddRef/Release are special and are not considered for the NOTXPCOM flag.
+ void SetHasNotXPCOMFlag()
+ {
+ mFlags.SetFlagBit(HASNOTXPCOM, true);
+ }
+ bool GetHasNotXPCOMFlag() const
+ {
+ return mFlags.GetFlagBit(HASNOTXPCOM);
+ }
+
+ const nsID* GetTheIID() const {return &mIID;}
+ const char* GetTheName() const {return mName;}
+
+ bool EnsureResolved()
+ {return IsFullyResolved() ? true : Resolve();}
+
+ already_AddRefed<xptiInterfaceInfo> InterfaceInfo();
+ bool InterfaceInfoEquals(const xptiInterfaceInfo* info) const
+ {return info == mInfo;}
+
+ void LockedInvalidateInterfaceInfo();
+ void LockedInterfaceInfoDeathNotification() {mInfo = nullptr;}
+
+ xptiInterfaceEntry* Parent() const {
+ NS_ASSERTION(IsFullyResolved(), "Parent() called while not resolved?");
+ return mParent;
+ }
+
+ const nsID& IID() const { return mIID; }
+
+ //////////////////////
+ // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
+
+ nsresult GetName(char * *aName);
+ nsresult GetIID(nsIID * *aIID);
+ nsresult IsScriptable(bool *_retval);
+ nsresult IsBuiltinClass(bool *_retval) {
+ *_retval = GetBuiltinClassFlag();
+ return NS_OK;
+ }
+ nsresult IsMainProcessScriptableOnly(bool *_retval) {
+ *_retval = GetMainProcessScriptableOnlyFlag();
+ return NS_OK;
+ }
+ // Except this one.
+ //nsresult GetParent(nsIInterfaceInfo * *aParent);
+ nsresult GetMethodCount(uint16_t *aMethodCount);
+ nsresult GetConstantCount(uint16_t *aConstantCount);
+ nsresult GetMethodInfo(uint16_t index, const nsXPTMethodInfo * *info);
+ nsresult GetMethodInfoForName(const char *methodName, uint16_t *index, const nsXPTMethodInfo * *info);
+ nsresult GetConstant(uint16_t index, JS::MutableHandleValue, char** constant);
+ nsresult GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval);
+ nsresult GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID * *_retval);
+ nsresult GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, nsXPTType *_retval);
+ nsresult GetSizeIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, uint8_t *_retval);
+ nsresult GetInterfaceIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint8_t *_retval);
+ nsresult IsIID(const nsIID * IID, bool *_retval);
+ nsresult GetNameShared(const char **name);
+ nsresult GetIIDShared(const nsIID * *iid);
+ nsresult IsFunction(bool *_retval);
+ nsresult HasAncestor(const nsIID * iid, bool *_retval);
+ nsresult GetIIDForParamNoAlloc(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID *iid);
+
+private:
+ xptiInterfaceEntry(const char* name,
+ size_t nameLength,
+ const nsID& iid,
+ XPTInterfaceDescriptor* aDescriptor,
+ xptiTypelibGuts* aTypelib);
+ ~xptiInterfaceEntry();
+
+ void SetResolvedState(int state)
+ {mFlags.SetState(uint8_t(state));}
+
+ bool Resolve();
+
+ // We only call these "*Locked" variants after locking. This is done to
+ // allow reentrace as files are loaded and various interfaces resolved
+ // without having to worry about the locked state.
+
+ bool EnsureResolvedLocked()
+ {return IsFullyResolved() ? true : ResolveLocked();}
+ bool ResolveLocked();
+
+ // private helpers
+
+ nsresult GetEntryForParam(uint16_t methodIndex,
+ const nsXPTParamInfo * param,
+ xptiInterfaceEntry** entry);
+
+ nsresult GetTypeInArray(const nsXPTParamInfo* param,
+ uint16_t dimension,
+ const XPTTypeDescriptor** type);
+
+ nsresult GetInterfaceIndexForParam(uint16_t methodIndex,
+ const nsXPTParamInfo* param,
+ uint16_t* interfaceIndex);
+
+ already_AddRefed<ShimInterfaceInfo>
+ GetShimForParam(uint16_t methodIndex, const nsXPTParamInfo* param);
+
+private:
+ nsID mIID;
+ XPTInterfaceDescriptor* mDescriptor;
+
+ xptiTypelibGuts* mTypelib;
+
+ xptiInterfaceEntry* mParent; // Valid only when fully resolved
+
+ xptiInterfaceInfo* MOZ_UNSAFE_REF("The safety of this pointer is ensured "
+ "by the semantics of xptiWorkingSet.")
+ mInfo; // May come and go.
+
+ uint16_t mMethodBaseIndex;
+ uint16_t mConstantBaseIndex;
+
+ xptiInfoFlags mFlags;
+
+ char mName[1]; // Always last. Sized to fit.
+};
+
+class xptiInterfaceInfo final : public nsIInterfaceInfo
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // Use delegation to implement (most!) of nsIInterfaceInfo.
+ NS_IMETHOD GetName(char * *aName) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); }
+ NS_IMETHOD GetInterfaceIID(nsIID * *aIID) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); }
+ NS_IMETHOD IsScriptable(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); }
+ NS_IMETHOD IsBuiltinClass(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsBuiltinClass(_retval); }
+ NS_IMETHOD IsMainProcessScriptableOnly(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsMainProcessScriptableOnly(_retval); }
+ // Except this one.
+ NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) override
+ {
+ if(!EnsureResolved() || !EnsureParent())
+ return NS_ERROR_UNEXPECTED;
+ NS_IF_ADDREF(*aParent = mParent);
+ return NS_OK;
+ }
+ NS_IMETHOD GetMethodCount(uint16_t *aMethodCount) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); }
+ NS_IMETHOD GetConstantCount(uint16_t *aConstantCount) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); }
+ NS_IMETHOD GetMethodInfo(uint16_t index, const nsXPTMethodInfo * *info) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); }
+ NS_IMETHOD GetMethodInfoForName(const char *methodName, uint16_t *index, const nsXPTMethodInfo * *info) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); }
+ NS_IMETHOD GetConstant(uint16_t index, JS::MutableHandleValue constant, char** name) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant, name); }
+ NS_IMETHOD GetInfoForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); }
+ NS_IMETHOD GetIIDForParam(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); }
+ NS_IMETHOD GetTypeForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, nsXPTType *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); }
+ NS_IMETHOD GetSizeIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint16_t dimension, uint8_t *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); }
+ NS_IMETHOD GetInterfaceIsArgNumberForParam(uint16_t methodIndex, const nsXPTParamInfo * param, uint8_t *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); }
+ NS_IMETHOD IsIID(const nsIID * IID, bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); }
+ NS_IMETHOD GetNameShared(const char **name) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); }
+ NS_IMETHOD GetIIDShared(const nsIID * *iid) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); }
+ NS_IMETHOD IsFunction(bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); }
+ NS_IMETHOD HasAncestor(const nsIID * iid, bool *_retval) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); }
+ NS_IMETHOD GetIIDForParamNoAlloc(uint16_t methodIndex, const nsXPTParamInfo * param, nsIID *iid) override { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); }
+
+public:
+ explicit xptiInterfaceInfo(xptiInterfaceEntry* entry);
+
+ void Invalidate();
+
+private:
+
+ ~xptiInterfaceInfo();
+
+ // Note that mParent might still end up as nullptr if we don't have one.
+ bool EnsureParent()
+ {
+ NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call");
+ return mParent || !mEntry->Parent() || BuildParent();
+ }
+
+ bool EnsureResolved()
+ {
+ return mEntry && mEntry->EnsureResolved();
+ }
+
+ bool BuildParent();
+
+ xptiInterfaceInfo(); // not implemented
+
+private:
+ xptiInterfaceEntry* mEntry;
+ RefPtr<xptiInterfaceInfo> mParent;
+};
+
+/***************************************************************************/
+
+#endif /* xptiprivate_h___ */