From a34d453ee82823f1c0557d345717dd426b62b1f7 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Tue, 29 Jan 2019 17:46:27 -0800 Subject: [PATCH] Bug 1524688: Part 1a - Support static registration JS components. r=mccr8 --HG-- extra : source : 68eb174a337b20e64583ae8afd45d479a3f54b61 --- build/docs/defining-xpcom-components.rst | 6 ++++ xpcom/components/StaticComponents.cpp.in | 37 +++++++++++++++++++++++ xpcom/components/gen_static_components.py | 21 +++++++++++-- xpcom/components/nsComponentManager.cpp | 2 ++ xpcom/components/nsComponentManager.h | 4 +++ 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/build/docs/defining-xpcom-components.rst b/build/docs/defining-xpcom-components.rst index 790007febb76..2621ad7d1f36 100644 --- a/build/docs/defining-xpcom-components.rst +++ b/build/docs/defining-xpcom-components.rst @@ -102,6 +102,12 @@ Class definitions may have the following properties: This property is incompatible with ``legacy_constructor``. +``jsm`` (optional) + If provided, must be the URL of a JavaScript module which contains a + JavaScript implementation of the component. The ``constructor`` property + must contain the name of an exported function which can be constructed to + create a new instance of the component. + ``legacy_constructor`` (optional) This property is deprecated, and should not be used in new code. diff --git a/xpcom/components/StaticComponents.cpp.in b/xpcom/components/StaticComponents.cpp.in index 8f718a2564cd..64b0e435e158 100644 --- a/xpcom/components/StaticComponents.cpp.in +++ b/xpcom/components/StaticComponents.cpp.in @@ -9,8 +9,11 @@ #include "mozilla/PerfectHash.h" #include "mozilla/ResultExtensions.h" #include "mozilla/StaticPtr.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozJSComponentLoader.h" #include "nsCOMPtr.h" #include "nsComponentManager.h" +#include "nsContentUtils.h" #include "nsIFactory.h" #include "nsISupports.h" #include "nsString.h" @@ -27,6 +30,9 @@ //# @decls@ namespace mozilla { + +using dom::AutoJSAPI; + namespace xpcom { static constexpr uint32_t kNoContractID = 0xffffffff; @@ -83,6 +89,37 @@ bool ContractEntry::Matches(const nsACString& aContractID) const { } +static nsresult ConstructJSMComponent(const nsACString& aURI, + const char* aConstructor, + nsISupports** aResult) { + if (!nsComponentManagerImpl::JSLoaderReady()) { + return NS_ERROR_NOT_AVAILABLE; + } + + AutoJSAPI jsapi; + MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope())); + JSContext* cx = jsapi.cx(); + + JS::RootedObject global(cx); + JS::RootedObject exports(cx); + MOZ_TRY(mozJSComponentLoader::Get()->Import(cx, aURI, &global, &exports)); + + JS::RootedValue ctor(cx); + if (!JS_GetProperty(cx, exports, aConstructor, &ctor) || + !ctor.isObject()) { + return NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED; + } + + JS::RootedObject inst(cx); + if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), &inst)) { + return NS_ERROR_FAILURE; + } + + return nsContentUtils::XPConnect()->WrapJS(cx, inst, NS_GET_IID(nsISupports), + (void**)aResult); +} + + //# @module_cid_table@ //# @module_contract_id_table@ diff --git a/xpcom/components/gen_static_components.py b/xpcom/components/gen_static_components.py index 04f09b26825a..f954c77edd17 100644 --- a/xpcom/components/gen_static_components.py +++ b/xpcom/components/gen_static_components.py @@ -218,6 +218,8 @@ class ModuleEntry(object): self.legacy_constructor = data.get('legacy_constructor', None) self.init_method = data.get('init_method', []) + self.jsm = data.get('jsm', None) + self.external = data.get('external', not (self.headers or self.legacy_constructor)) self.singleton = data.get('singleton', False) @@ -236,7 +238,15 @@ class ModuleEntry(object): str(self.cid), ', '.join(map(repr, self.contract_ids)), str_)) - if self.external: + if self.jsm: + if not self.constructor: + error("JavaScript components must specify a constructor") + + for prop in ('init_method', 'legacy_constructor', 'headers'): + if getattr(self, prop): + error("JavaScript components may not specify a '%s' " + "property" % prop) + elif self.external: if self.constructor or self.legacy_constructor: error("Externally-constructed components may not specify " "'constructor' or 'legacy_constructor' properties") @@ -299,7 +309,14 @@ class ModuleEntry(object): % self.legacy_constructor) return res - if self.external: + if self.jsm: + res += ( + ' nsCOMPtr inst;\n' + ' MOZ_TRY(ConstructJSMComponent(NS_LITERAL_CSTRING(%s),\n' + ' %s,\n' + ' getter_AddRefs(inst)));' + '\n' % (json.dumps(self.jsm), json.dumps(self.constructor))) + elif self.external: res += (' nsCOMPtr inst = ' 'mozCreateComponent<%s>();\n' % self.type) else: diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index 34588e902d7b..8b5f6428158e 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -531,6 +531,8 @@ nsresult nsComponentManagerImpl::Init() { // used, and before any calls are made into the JS engine. nsLayoutModuleInitialize(); + mJSLoaderReady = true; + // The overall order in which chrome.manifests are expected to be treated // is the following: // - greDir diff --git a/xpcom/components/nsComponentManager.h b/xpcom/components/nsComponentManager.h index a1f988ca694a..a03afa8fe26e 100644 --- a/xpcom/components/nsComponentManager.h +++ b/xpcom/components/nsComponentManager.h @@ -166,6 +166,8 @@ class nsComponentManagerImpl final : public nsIComponentManager, nsresult GetService(mozilla::xpcom::ModuleID, const nsIID& aIID, void** aResult); + static bool JSLoaderReady() { return gComponentManager->mJSLoaderReady; } + static void InitializeStaticModules(); static void InitializeModuleLocations(); @@ -281,6 +283,8 @@ class nsComponentManagerImpl final : public nsIComponentManager, nsTArray mPendingServices; + bool mJSLoaderReady = false; + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; private: