diff options
Diffstat (limited to 'xpcom/reflect/xptinfo')
-rw-r--r-- | xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp | 700 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/ShimInterfaceInfo.h | 50 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/TODO | 20 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/XPTInterfaceInfoManager.h | 119 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/moz.build | 37 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/nsIInterfaceInfo.idl | 101 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/nsIInterfaceInfoManager.idl | 28 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/xptiInterfaceInfo.cpp | 742 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp | 242 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/xptiTypelibGuts.cpp | 74 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/xptiWorkingSet.cpp | 53 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/xptinfo.h | 236 | ||||
-rw-r--r-- | xpcom/reflect/xptinfo/xptiprivate.h | 394 |
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 000000000..14e719f6c --- /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 000000000..868f503a5 --- /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 000000000..50215a4fb --- /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 000000000..e72153ad2 --- /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 000000000..320949782 --- /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 000000000..8b902d5ee --- /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 000000000..bc63aed49 --- /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 000000000..8ea80fda1 --- /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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 000000000..600a99b94 --- /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 000000000..e2965d0b1 --- /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 000000000..10f81a4b2 --- /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 000000000..1207a42bb --- /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 000000000..c32ef9c77 --- /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___ */ |