1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /* The "Components" xpcom objects for JavaScript. */
8 
9 #include "xpcprivate.h"
10 #include "xpc_make_class.h"
11 #include "JSServices.h"
12 #include "XPCJSWeakReference.h"
13 #include "WrapperFactory.h"
14 #include "nsJSUtils.h"
15 #include "mozJSComponentLoader.h"
16 #include "nsContentUtils.h"
17 #include "nsCycleCollector.h"
18 #include "jsfriendapi.h"
19 #include "js/Array.h"  // JS::IsArrayObject
20 #include "js/CharacterEncoding.h"
21 #include "js/ContextOptions.h"
22 #include "js/friend/WindowProxy.h"  // js::ToWindowProxyIfWindow
23 #include "js/Object.h"              // JS::GetClass, JS::GetCompartment
24 #include "js/SavedFrameAPI.h"
25 #include "js/StructuredClone.h"
26 #include "mozilla/AppShutdown.h"
27 #include "mozilla/Attributes.h"
28 #include "mozilla/LoadContext.h"
29 #include "mozilla/Preferences.h"
30 #include "nsJSEnvironment.h"
31 #include "mozilla/BasePrincipal.h"
32 #include "mozilla/TimeStamp.h"
33 #include "mozilla/ResultExtensions.h"
34 #include "mozilla/URLPreloader.h"
35 #include "mozilla/dom/DOMException.h"
36 #include "mozilla/dom/DOMExceptionBinding.h"
37 #include "mozilla/dom/BindingUtils.h"
38 #include "mozilla/dom/RemoteObjectProxy.h"
39 #include "mozilla/dom/StructuredCloneTags.h"
40 #include "mozilla/dom/WindowBinding.h"
41 #include "nsZipArchive.h"
42 #include "nsWindowMemoryReporter.h"
43 #include "nsICycleCollectorListener.h"
44 #include "nsIException.h"
45 #include "nsIScriptError.h"
46 #include "nsPIDOMWindow.h"
47 #include "nsGlobalWindow.h"
48 #include "nsScriptError.h"
49 #include "GeckoProfiler.h"
50 #include "mozilla/EditorSpellCheck.h"
51 #include "nsCommandLine.h"
52 #include "nsCommandParams.h"
53 #include "nsPersistentProperties.h"
54 #include "nsIDocumentEncoder.h"
55 
56 using namespace mozilla;
57 using namespace JS;
58 using namespace js;
59 using namespace xpc;
60 using mozilla::dom::Exception;
61 
62 /***************************************************************************/
63 // stuff used by all
64 
ThrowAndFail(nsresult errNum,JSContext * cx,bool * retval)65 nsresult xpc::ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval) {
66   XPCThrower::Throw(errNum, cx);
67   *retval = false;
68   return NS_OK;
69 }
70 
JSValIsInterfaceOfType(JSContext * cx,HandleValue v,REFNSIID iid)71 static bool JSValIsInterfaceOfType(JSContext* cx, HandleValue v, REFNSIID iid) {
72   nsCOMPtr<nsIXPConnectWrappedNative> wn;
73   nsCOMPtr<nsISupports> iface;
74 
75   if (v.isPrimitive()) {
76     return false;
77   }
78 
79   nsIXPConnect* xpc = nsIXPConnect::XPConnect();
80   RootedObject obj(cx, &v.toObject());
81   return NS_SUCCEEDED(
82              xpc->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wn))) &&
83          wn &&
84          NS_SUCCEEDED(
85              wn->Native()->QueryInterface(iid, getter_AddRefs(iface))) &&
86          iface;
87 }
88 
89 /***************************************************************************/
90 /***************************************************************************/
91 /***************************************************************************/
92 
93 class nsXPCComponents_Interfaces final : public nsIXPCComponents_Interfaces,
94                                          public nsIXPCScriptable,
95                                          public nsIClassInfo {
96  public:
97   // all the interface method declarations...
98   NS_DECL_ISUPPORTS
99   NS_DECL_NSIXPCCOMPONENTS_INTERFACES
100   NS_DECL_NSIXPCSCRIPTABLE
101   NS_DECL_NSICLASSINFO
102 
103  public:
104   nsXPCComponents_Interfaces();
105 
106  private:
107   virtual ~nsXPCComponents_Interfaces();
108 };
109 
110 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & aArray)111 nsXPCComponents_Interfaces::GetInterfaces(nsTArray<nsIID>& aArray) {
112   aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Interfaces),
113                            NS_GET_IID(nsIXPCScriptable)};
114   return NS_OK;
115 }
116 
117 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)118 nsXPCComponents_Interfaces::GetScriptableHelper(nsIXPCScriptable** retval) {
119   *retval = nullptr;
120   return NS_OK;
121 }
122 
123 NS_IMETHODIMP
GetContractID(nsACString & aContractID)124 nsXPCComponents_Interfaces::GetContractID(nsACString& aContractID) {
125   aContractID.SetIsVoid(true);
126   return NS_ERROR_NOT_AVAILABLE;
127 }
128 
129 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)130 nsXPCComponents_Interfaces::GetClassDescription(nsACString& aClassDescription) {
131   aClassDescription.AssignLiteral("XPCComponents_Interfaces");
132   return NS_OK;
133 }
134 
135 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)136 nsXPCComponents_Interfaces::GetClassID(nsCID** aClassID) {
137   *aClassID = nullptr;
138   return NS_OK;
139 }
140 
141 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)142 nsXPCComponents_Interfaces::GetFlags(uint32_t* aFlags) {
143   *aFlags = 0;
144   return NS_OK;
145 }
146 
147 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)148 nsXPCComponents_Interfaces::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
149   return NS_ERROR_NOT_AVAILABLE;
150 }
151 
152 nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() = default;
153 
~nsXPCComponents_Interfaces()154 nsXPCComponents_Interfaces::~nsXPCComponents_Interfaces() {
155   // empty
156 }
157 
158 NS_IMPL_ISUPPORTS(nsXPCComponents_Interfaces, nsIXPCComponents_Interfaces,
159                   nsIXPCScriptable, nsIClassInfo);
160 
161 // The nsIXPCScriptable map declaration that will generate stubs for us...
162 #define XPC_MAP_CLASSNAME nsXPCComponents_Interfaces
163 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Interfaces"
164 #define XPC_MAP_FLAGS                                               \
165   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
166    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
167 #include "xpc_map_end.h" /* This will #undef the above */
168 
169 NS_IMETHODIMP
NewEnumerate(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,JS::MutableHandleIdVector properties,bool enumerableOnly,bool * _retval)170 nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
171                                          JSContext* cx, JSObject* obj,
172                                          JS::MutableHandleIdVector properties,
173                                          bool enumerableOnly, bool* _retval) {
174   if (!properties.reserve(nsXPTInterfaceInfo::InterfaceCount())) {
175     *_retval = false;
176     return NS_OK;
177   }
178 
179   for (uint32_t index = 0; index < nsXPTInterfaceInfo::InterfaceCount();
180        index++) {
181     const nsXPTInterfaceInfo* interface = nsXPTInterfaceInfo::ByIndex(index);
182     if (!interface) {
183       continue;
184     }
185 
186     const char* name = interface->Name();
187     if (!name) {
188       continue;
189     }
190 
191     RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
192     if (!idstr) {
193       *_retval = false;
194       return NS_OK;
195     }
196 
197     RootedId id(cx);
198     if (!JS_StringToId(cx, idstr, &id)) {
199       *_retval = false;
200       return NS_OK;
201     }
202 
203     properties.infallibleAppend(id);
204   }
205 
206   return NS_OK;
207 }
208 
209 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)210 nsXPCComponents_Interfaces::Resolve(nsIXPConnectWrappedNative* wrapper,
211                                     JSContext* cx, JSObject* objArg, jsid idArg,
212                                     bool* resolvedp, bool* _retval) {
213   RootedObject obj(cx, objArg);
214   RootedId id(cx, idArg);
215 
216   if (!JSID_IS_STRING(id)) {
217     return NS_OK;
218   }
219 
220   RootedString str(cx, JSID_TO_STRING(id));
221   JS::UniqueChars name = JS_EncodeStringToLatin1(cx, str);
222 
223   // we only allow interfaces by name here
224   if (name && name[0] != '{') {
225     const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByName(name.get());
226     if (!info) {
227       return NS_OK;
228     }
229 
230     RootedValue iidv(cx);
231     if (xpc::IfaceID2JSValue(cx, *info, &iidv)) {
232       *resolvedp = true;
233       *_retval = JS_DefinePropertyById(cx, obj, id, iidv,
234                                        JSPROP_ENUMERATE | JSPROP_READONLY |
235                                            JSPROP_PERMANENT | JSPROP_RESOLVING);
236     }
237   }
238   return NS_OK;
239 }
240 
241 /***************************************************************************/
242 /***************************************************************************/
243 /***************************************************************************/
244 
245 class nsXPCComponents_Classes final : public nsIXPCComponents_Classes,
246                                       public nsIXPCScriptable,
247                                       public nsIClassInfo {
248  public:
249   // all the interface method declarations...
250   NS_DECL_ISUPPORTS
251   NS_DECL_NSIXPCCOMPONENTS_CLASSES
252   NS_DECL_NSIXPCSCRIPTABLE
253   NS_DECL_NSICLASSINFO
254 
255  public:
256   nsXPCComponents_Classes();
257 
258  private:
259   virtual ~nsXPCComponents_Classes();
260 };
261 
262 /***************************************************************************/
263 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & aArray)264 nsXPCComponents_Classes::GetInterfaces(nsTArray<nsIID>& aArray) {
265   aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Classes),
266                            NS_GET_IID(nsIXPCScriptable)};
267   return NS_OK;
268 }
269 
270 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)271 nsXPCComponents_Classes::GetScriptableHelper(nsIXPCScriptable** retval) {
272   *retval = nullptr;
273   return NS_OK;
274 }
275 
276 NS_IMETHODIMP
GetContractID(nsACString & aContractID)277 nsXPCComponents_Classes::GetContractID(nsACString& aContractID) {
278   aContractID.SetIsVoid(true);
279   return NS_ERROR_NOT_AVAILABLE;
280 }
281 
282 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)283 nsXPCComponents_Classes::GetClassDescription(nsACString& aClassDescription) {
284   aClassDescription.AssignLiteral("XPCComponents_Classes");
285   return NS_OK;
286 }
287 
288 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)289 nsXPCComponents_Classes::GetClassID(nsCID** aClassID) {
290   *aClassID = nullptr;
291   return NS_OK;
292 }
293 
294 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)295 nsXPCComponents_Classes::GetFlags(uint32_t* aFlags) {
296   *aFlags = 0;
297   return NS_OK;
298 }
299 
300 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)301 nsXPCComponents_Classes::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
302   return NS_ERROR_NOT_AVAILABLE;
303 }
304 
305 nsXPCComponents_Classes::nsXPCComponents_Classes() = default;
306 
~nsXPCComponents_Classes()307 nsXPCComponents_Classes::~nsXPCComponents_Classes() {
308   // empty
309 }
310 
NS_IMPL_ISUPPORTS(nsXPCComponents_Classes,nsIXPCComponents_Classes,nsIXPCScriptable,nsIClassInfo)311 NS_IMPL_ISUPPORTS(nsXPCComponents_Classes, nsIXPCComponents_Classes,
312                   nsIXPCScriptable, nsIClassInfo)
313 
314 // The nsIXPCScriptable map declaration that will generate stubs for us...
315 #define XPC_MAP_CLASSNAME nsXPCComponents_Classes
316 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Classes"
317 #define XPC_MAP_FLAGS                                               \
318   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
319    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
320 #include "xpc_map_end.h" /* This will #undef the above */
321 
322 NS_IMETHODIMP
323 nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
324                                       JSContext* cx, JSObject* obj,
325                                       JS::MutableHandleIdVector properties,
326                                       bool enumerableOnly, bool* _retval) {
327   nsCOMPtr<nsIComponentRegistrar> compMgr;
328   if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) ||
329       !compMgr) {
330     return NS_ERROR_UNEXPECTED;
331   }
332 
333   nsTArray<nsCString> contractIDs;
334   if (NS_FAILED(compMgr->GetContractIDs(contractIDs))) {
335     return NS_ERROR_UNEXPECTED;
336   }
337 
338   for (const auto& name : contractIDs) {
339     RootedString idstr(cx, JS_NewStringCopyN(cx, name.get(), name.Length()));
340     if (!idstr) {
341       *_retval = false;
342       return NS_OK;
343     }
344 
345     RootedId id(cx);
346     if (!JS_StringToId(cx, idstr, &id)) {
347       *_retval = false;
348       return NS_OK;
349     }
350 
351     if (!properties.append(id)) {
352       *_retval = false;
353       return NS_OK;
354     }
355   }
356 
357   return NS_OK;
358 }
359 
360 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)361 nsXPCComponents_Classes::Resolve(nsIXPConnectWrappedNative* wrapper,
362                                  JSContext* cx, JSObject* objArg, jsid idArg,
363                                  bool* resolvedp, bool* _retval)
364 
365 {
366   RootedId id(cx, idArg);
367   RootedObject obj(cx, objArg);
368 
369   RootedValue cidv(cx);
370   if (JSID_IS_STRING(id) &&
371       xpc::ContractID2JSValue(cx, JSID_TO_STRING(id), &cidv)) {
372     *resolvedp = true;
373     *_retval = JS_DefinePropertyById(cx, obj, id, cidv,
374                                      JSPROP_ENUMERATE | JSPROP_READONLY |
375                                          JSPROP_PERMANENT | JSPROP_RESOLVING);
376   }
377   return NS_OK;
378 }
379 
380 /***************************************************************************/
381 /***************************************************************************/
382 /***************************************************************************/
383 
384 // Currently the possible results do not change at runtime, so they are only
385 // cached once (unlike ContractIDs, CLSIDs, and IIDs)
386 
387 class nsXPCComponents_Results final : public nsIXPCComponents_Results,
388                                       public nsIXPCScriptable,
389                                       public nsIClassInfo {
390  public:
391   // all the interface method declarations...
392   NS_DECL_ISUPPORTS
393   NS_DECL_NSIXPCCOMPONENTS_RESULTS
394   NS_DECL_NSIXPCSCRIPTABLE
395   NS_DECL_NSICLASSINFO
396 
397  public:
398   nsXPCComponents_Results();
399 
400  private:
401   virtual ~nsXPCComponents_Results();
402 };
403 
404 /***************************************************************************/
405 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & aArray)406 nsXPCComponents_Results::GetInterfaces(nsTArray<nsIID>& aArray) {
407   aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Results),
408                            NS_GET_IID(nsIXPCScriptable)};
409   return NS_OK;
410 }
411 
412 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)413 nsXPCComponents_Results::GetScriptableHelper(nsIXPCScriptable** retval) {
414   *retval = nullptr;
415   return NS_OK;
416 }
417 
418 NS_IMETHODIMP
GetContractID(nsACString & aContractID)419 nsXPCComponents_Results::GetContractID(nsACString& aContractID) {
420   aContractID.SetIsVoid(true);
421   return NS_ERROR_NOT_AVAILABLE;
422 }
423 
424 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)425 nsXPCComponents_Results::GetClassDescription(nsACString& aClassDescription) {
426   aClassDescription.AssignLiteral("XPCComponents_Results");
427   return NS_OK;
428 }
429 
430 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)431 nsXPCComponents_Results::GetClassID(nsCID** aClassID) {
432   *aClassID = nullptr;
433   return NS_OK;
434 }
435 
436 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)437 nsXPCComponents_Results::GetFlags(uint32_t* aFlags) {
438   *aFlags = 0;
439   return NS_OK;
440 }
441 
442 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)443 nsXPCComponents_Results::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
444   return NS_ERROR_NOT_AVAILABLE;
445 }
446 
447 nsXPCComponents_Results::nsXPCComponents_Results() = default;
448 
~nsXPCComponents_Results()449 nsXPCComponents_Results::~nsXPCComponents_Results() {
450   // empty
451 }
452 
NS_IMPL_ISUPPORTS(nsXPCComponents_Results,nsIXPCComponents_Results,nsIXPCScriptable,nsIClassInfo)453 NS_IMPL_ISUPPORTS(nsXPCComponents_Results, nsIXPCComponents_Results,
454                   nsIXPCScriptable, nsIClassInfo)
455 
456 // The nsIXPCScriptable map declaration that will generate stubs for us...
457 #define XPC_MAP_CLASSNAME nsXPCComponents_Results
458 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Results"
459 #define XPC_MAP_FLAGS                                               \
460   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
461    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
462 #include "xpc_map_end.h" /* This will #undef the above */
463 
464 NS_IMETHODIMP
465 nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
466                                       JSContext* cx, JSObject* obj,
467                                       JS::MutableHandleIdVector properties,
468                                       bool enumerableOnly, bool* _retval) {
469   const char* name;
470   const void* iter = nullptr;
471   while (nsXPCException::IterateNSResults(nullptr, &name, nullptr, &iter)) {
472     RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
473     if (!idstr) {
474       *_retval = false;
475       return NS_OK;
476     }
477 
478     RootedId id(cx);
479     if (!JS_StringToId(cx, idstr, &id)) {
480       *_retval = false;
481       return NS_OK;
482     }
483 
484     if (!properties.append(id)) {
485       *_retval = false;
486       return NS_OK;
487     }
488   }
489 
490   return NS_OK;
491 }
492 
493 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)494 nsXPCComponents_Results::Resolve(nsIXPConnectWrappedNative* wrapper,
495                                  JSContext* cx, JSObject* objArg, jsid idArg,
496                                  bool* resolvedp, bool* _retval) {
497   RootedObject obj(cx, objArg);
498   RootedId id(cx, idArg);
499   if (!JSID_IS_STRING(id)) {
500     return NS_OK;
501   }
502 
503   JS::UniqueChars name = JS_EncodeStringToLatin1(cx, JSID_TO_STRING(id));
504   if (name) {
505     const char* rv_name;
506     const void* iter = nullptr;
507     nsresult rv;
508     while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) {
509       if (!strcmp(name.get(), rv_name)) {
510         *resolvedp = true;
511         if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv,
512                                    JSPROP_ENUMERATE | JSPROP_READONLY |
513                                        JSPROP_PERMANENT | JSPROP_RESOLVING)) {
514           return NS_ERROR_UNEXPECTED;
515         }
516       }
517     }
518   }
519   return NS_OK;
520 }
521 
522 /***************************************************************************/
523 // JavaScript Constructor for nsIJSID objects (Components.ID)
524 
525 class nsXPCComponents_ID final : public nsIXPCComponents_ID,
526                                  public nsIXPCScriptable,
527                                  public nsIClassInfo {
528  public:
529   // all the interface method declarations...
530   NS_DECL_ISUPPORTS
531   NS_DECL_NSIXPCCOMPONENTS_ID
532   NS_DECL_NSIXPCSCRIPTABLE
533   NS_DECL_NSICLASSINFO
534 
535  public:
536   nsXPCComponents_ID();
537 
538  private:
539   virtual ~nsXPCComponents_ID();
540   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
541                                   JSContext* cx, HandleObject obj,
542                                   const CallArgs& args, bool* _retval);
543 };
544 
545 /***************************************************************************/
546 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & aArray)547 nsXPCComponents_ID::GetInterfaces(nsTArray<nsIID>& aArray) {
548   aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_ID),
549                            NS_GET_IID(nsIXPCScriptable)};
550   return NS_OK;
551 }
552 
553 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)554 nsXPCComponents_ID::GetScriptableHelper(nsIXPCScriptable** retval) {
555   *retval = nullptr;
556   return NS_OK;
557 }
558 
559 NS_IMETHODIMP
GetContractID(nsACString & aContractID)560 nsXPCComponents_ID::GetContractID(nsACString& aContractID) {
561   aContractID.SetIsVoid(true);
562   return NS_ERROR_NOT_AVAILABLE;
563 }
564 
565 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)566 nsXPCComponents_ID::GetClassDescription(nsACString& aClassDescription) {
567   aClassDescription.AssignLiteral("XPCComponents_ID");
568   return NS_OK;
569 }
570 
571 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)572 nsXPCComponents_ID::GetClassID(nsCID** aClassID) {
573   *aClassID = nullptr;
574   return NS_OK;
575 }
576 
577 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)578 nsXPCComponents_ID::GetFlags(uint32_t* aFlags) {
579   *aFlags = 0;
580   return NS_OK;
581 }
582 
583 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)584 nsXPCComponents_ID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
585   return NS_ERROR_NOT_AVAILABLE;
586 }
587 
588 nsXPCComponents_ID::nsXPCComponents_ID() = default;
589 
~nsXPCComponents_ID()590 nsXPCComponents_ID::~nsXPCComponents_ID() {
591   // empty
592 }
593 
NS_IMPL_ISUPPORTS(nsXPCComponents_ID,nsIXPCComponents_ID,nsIXPCScriptable,nsIClassInfo)594 NS_IMPL_ISUPPORTS(nsXPCComponents_ID, nsIXPCComponents_ID, nsIXPCScriptable,
595                   nsIClassInfo)
596 
597 // The nsIXPCScriptable map declaration that will generate stubs for us...
598 #define XPC_MAP_CLASSNAME nsXPCComponents_ID
599 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ID"
600 #define XPC_MAP_FLAGS                                         \
601   (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
602    XPC_SCRIPTABLE_WANT_HASINSTANCE |                          \
603    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
604 #include "xpc_map_end.h" /* This will #undef the above */
605 
606 NS_IMETHODIMP
607 nsXPCComponents_ID::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
608                          JSObject* objArg, const CallArgs& args,
609                          bool* _retval) {
610   RootedObject obj(cx, objArg);
611   return CallOrConstruct(wrapper, cx, obj, args, _retval);
612 }
613 
614 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)615 nsXPCComponents_ID::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
616                               JSObject* objArg, const CallArgs& args,
617                               bool* _retval) {
618   RootedObject obj(cx, objArg);
619   return CallOrConstruct(wrapper, cx, obj, args, _retval);
620 }
621 
622 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)623 nsresult nsXPCComponents_ID::CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
624                                              JSContext* cx, HandleObject obj,
625                                              const CallArgs& args,
626                                              bool* _retval) {
627   // make sure we have at least one arg
628 
629   if (args.length() < 1) {
630     return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
631   }
632 
633   // Prevent non-chrome code from creating ID objects.
634   if (!nsContentUtils::IsCallerChrome()) {
635     return ThrowAndFail(NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED, cx, _retval);
636   }
637 
638   // convert the first argument into a string and see if it looks like an id
639 
640   JSString* jsstr = ToString(cx, args[0]);
641   if (!jsstr) {
642     return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
643   }
644 
645   JS::UniqueChars bytes = JS_EncodeStringToLatin1(cx, jsstr);
646   if (!bytes) {
647     return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
648   }
649 
650   nsID id;
651   if (!id.Parse(bytes.get())) {
652     return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
653   }
654 
655   // make the new object and return it.
656 
657   if (!xpc::ID2JSValue(cx, id, args.rval())) {
658     return NS_ERROR_UNEXPECTED;
659   }
660   return NS_OK;
661 }
662 
663 NS_IMETHODIMP
HasInstance(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,HandleValue val,bool * bp,bool * _retval)664 nsXPCComponents_ID::HasInstance(nsIXPConnectWrappedNative* wrapper,
665                                 JSContext* cx, JSObject* obj, HandleValue val,
666                                 bool* bp, bool* _retval) {
667   if (bp) {
668     *bp = xpc::JSValue2ID(cx, val).isSome();
669   }
670   return NS_OK;
671 }
672 
673 /***************************************************************************/
674 // JavaScript Constructor for Exception objects (Components.Exception)
675 
676 class nsXPCComponents_Exception final : public nsIXPCComponents_Exception,
677                                         public nsIXPCScriptable,
678                                         public nsIClassInfo {
679  public:
680   // all the interface method declarations...
681   NS_DECL_ISUPPORTS
682   NS_DECL_NSIXPCCOMPONENTS_EXCEPTION
683   NS_DECL_NSIXPCSCRIPTABLE
684   NS_DECL_NSICLASSINFO
685 
686  public:
687   nsXPCComponents_Exception();
688 
689  private:
690   virtual ~nsXPCComponents_Exception();
691   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
692                                   JSContext* cx, HandleObject obj,
693                                   const CallArgs& args, bool* _retval);
694 };
695 
696 /***************************************************************************/
697 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & aArray)698 nsXPCComponents_Exception::GetInterfaces(nsTArray<nsIID>& aArray) {
699   aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Exception),
700                            NS_GET_IID(nsIXPCScriptable)};
701   return NS_OK;
702 }
703 
704 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)705 nsXPCComponents_Exception::GetScriptableHelper(nsIXPCScriptable** retval) {
706   *retval = nullptr;
707   return NS_OK;
708 }
709 
710 NS_IMETHODIMP
GetContractID(nsACString & aContractID)711 nsXPCComponents_Exception::GetContractID(nsACString& aContractID) {
712   aContractID.SetIsVoid(true);
713   return NS_ERROR_NOT_AVAILABLE;
714 }
715 
716 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)717 nsXPCComponents_Exception::GetClassDescription(nsACString& aClassDescription) {
718   aClassDescription.AssignLiteral("XPCComponents_Exception");
719   return NS_OK;
720 }
721 
722 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)723 nsXPCComponents_Exception::GetClassID(nsCID** aClassID) {
724   *aClassID = nullptr;
725   return NS_OK;
726 }
727 
728 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)729 nsXPCComponents_Exception::GetFlags(uint32_t* aFlags) {
730   *aFlags = 0;
731   return NS_OK;
732 }
733 
734 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)735 nsXPCComponents_Exception::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
736   return NS_ERROR_NOT_AVAILABLE;
737 }
738 
739 nsXPCComponents_Exception::nsXPCComponents_Exception() = default;
740 
~nsXPCComponents_Exception()741 nsXPCComponents_Exception::~nsXPCComponents_Exception() {
742   // empty
743 }
744 
NS_IMPL_ISUPPORTS(nsXPCComponents_Exception,nsIXPCComponents_Exception,nsIXPCScriptable,nsIClassInfo)745 NS_IMPL_ISUPPORTS(nsXPCComponents_Exception, nsIXPCComponents_Exception,
746                   nsIXPCScriptable, nsIClassInfo)
747 
748 // The nsIXPCScriptable map declaration that will generate stubs for us...
749 #define XPC_MAP_CLASSNAME nsXPCComponents_Exception
750 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Exception"
751 #define XPC_MAP_FLAGS                                         \
752   (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
753    XPC_SCRIPTABLE_WANT_HASINSTANCE |                          \
754    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
755 #include "xpc_map_end.h" /* This will #undef the above */
756 
757 NS_IMETHODIMP
758 nsXPCComponents_Exception::Call(nsIXPConnectWrappedNative* wrapper,
759                                 JSContext* cx, JSObject* objArg,
760                                 const CallArgs& args, bool* _retval) {
761   RootedObject obj(cx, objArg);
762   return CallOrConstruct(wrapper, cx, obj, args, _retval);
763 }
764 
765 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)766 nsXPCComponents_Exception::Construct(nsIXPConnectWrappedNative* wrapper,
767                                      JSContext* cx, JSObject* objArg,
768                                      const CallArgs& args, bool* _retval) {
769   RootedObject obj(cx, objArg);
770   return CallOrConstruct(wrapper, cx, obj, args, _retval);
771 }
772 
773 struct MOZ_STACK_CLASS ExceptionArgParser {
ExceptionArgParserExceptionArgParser774   ExceptionArgParser(JSContext* context, nsIXPConnect* xpconnect)
775       : eMsg("exception"),
776         eResult(NS_ERROR_FAILURE),
777         cx(context),
778         xpc(xpconnect) {}
779 
780   // Public exception parameter values. During construction, these are
781   // initialized to the appropriate defaults.
782   const char* eMsg;
783   nsresult eResult;
784   nsCOMPtr<nsIStackFrame> eStack;
785   nsCOMPtr<nsISupports> eData;
786 
787   // Parse the constructor arguments into the above |eFoo| parameter values.
parseExceptionArgParser788   bool parse(const CallArgs& args) {
789     /*
790      * The Components.Exception takes a series of arguments, all of them
791      * optional:
792      *
793      * Argument 0: Exception message (defaults to 'exception').
794      * Argument 1: Result code (defaults to NS_ERROR_FAILURE) _or_ options
795      *             object (see below).
796      * Argument 2: Stack (defaults to the current stack, which we trigger
797      *                    by leaving this nullptr in the parser).
798      * Argument 3: Optional user data (defaults to nullptr).
799      *
800      * To dig our way out of this clunky API, we now support passing an
801      * options object as the second parameter (as opposed to a result code).
802      * If this is the case, all subsequent arguments are ignored, and the
803      * following properties are parsed out of the object (using the
804      * associated default if the property does not exist):
805      *
806      *   result:    Result code (see argument 1).
807      *   stack:     Call stack (see argument 2).
808      *   data:      User data (see argument 3).
809      */
810     if (args.length() > 0 && !parseMessage(args[0])) {
811       return false;
812     }
813     if (args.length() > 1) {
814       if (args[1].isObject()) {
815         RootedObject obj(cx, &args[1].toObject());
816         return parseOptionsObject(obj);
817       }
818       if (!parseResult(args[1])) {
819         return false;
820       }
821     }
822     if (args.length() > 2) {
823       if (!parseStack(args[2])) {
824         return false;
825       }
826     }
827     if (args.length() > 3) {
828       if (!parseData(args[3])) {
829         return false;
830       }
831     }
832     return true;
833   }
834 
835  protected:
836   /*
837    * Parsing helpers.
838    */
839 
parseMessageExceptionArgParser840   bool parseMessage(HandleValue v) {
841     JSString* str = ToString(cx, v);
842     if (!str) {
843       return false;
844     }
845     messageBytes = JS_EncodeStringToLatin1(cx, str);
846     eMsg = messageBytes.get();
847     return !!eMsg;
848   }
849 
parseResultExceptionArgParser850   bool parseResult(HandleValue v) {
851     return JS::ToUint32(cx, v, (uint32_t*)&eResult);
852   }
853 
parseStackExceptionArgParser854   bool parseStack(HandleValue v) {
855     if (!v.isObject()) {
856       // eStack has already been initialized to null, which is what we want
857       // for any non-object values (including null).
858       return true;
859     }
860 
861     RootedObject stackObj(cx, &v.toObject());
862     return NS_SUCCEEDED(xpc->WrapJS(cx, stackObj, NS_GET_IID(nsIStackFrame),
863                                     getter_AddRefs(eStack)));
864   }
865 
parseDataExceptionArgParser866   bool parseData(HandleValue v) {
867     if (!v.isObject()) {
868       // eData has already been initialized to null, which is what we want
869       // for any non-object values (including null).
870       return true;
871     }
872 
873     RootedObject obj(cx, &v.toObject());
874     return NS_SUCCEEDED(
875         xpc->WrapJS(cx, obj, NS_GET_IID(nsISupports), getter_AddRefs(eData)));
876   }
877 
parseOptionsObjectExceptionArgParser878   bool parseOptionsObject(HandleObject obj) {
879     RootedValue v(cx);
880 
881     if (!getOption(obj, "result", &v) || (!v.isUndefined() && !parseResult(v)))
882       return false;
883 
884     if (!getOption(obj, "stack", &v) || (!v.isUndefined() && !parseStack(v)))
885       return false;
886 
887     if (!getOption(obj, "data", &v) || (!v.isUndefined() && !parseData(v)))
888       return false;
889 
890     return true;
891   }
892 
getOptionExceptionArgParser893   bool getOption(HandleObject obj, const char* name, MutableHandleValue rv) {
894     // Look for the property.
895     bool found;
896     if (!JS_HasProperty(cx, obj, name, &found)) {
897       return false;
898     }
899 
900     // If it wasn't found, indicate with undefined.
901     if (!found) {
902       rv.setUndefined();
903       return true;
904     }
905 
906     // Get the property.
907     return JS_GetProperty(cx, obj, name, rv);
908   }
909 
910   /*
911    * Internal data members.
912    */
913 
914   // If there's a non-default exception string, hold onto the allocated bytes.
915   JS::UniqueChars messageBytes;
916 
917   // Various bits and pieces that are helpful to have around.
918   JSContext* cx;
919   nsIXPConnect* xpc;
920 };
921 
922 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)923 nsresult nsXPCComponents_Exception::CallOrConstruct(
924     nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj,
925     const CallArgs& args, bool* _retval) {
926   nsIXPConnect* xpc = nsIXPConnect::XPConnect();
927 
928   MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsCallerChrome());
929 
930   // Parse the arguments to the Exception constructor.
931   ExceptionArgParser parser(cx, xpc);
932   if (!parser.parse(args)) {
933     return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
934   }
935 
936   RefPtr<Exception> e = new Exception(nsCString(parser.eMsg), parser.eResult,
937                                       ""_ns, parser.eStack, parser.eData);
938 
939   RootedObject newObj(cx);
940   if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIException),
941                                 newObj.address())) ||
942       !newObj) {
943     return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
944   }
945 
946   args.rval().setObject(*newObj);
947   return NS_OK;
948 }
949 
950 NS_IMETHODIMP
HasInstance(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,HandleValue val,bool * bp,bool * _retval)951 nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative* wrapper,
952                                        JSContext* cx, JSObject* obj,
953                                        HandleValue val, bool* bp,
954                                        bool* _retval) {
955   using namespace mozilla::dom;
956 
957   if (bp) {
958     *bp = (val.isObject() && IS_INSTANCE_OF(Exception, &val.toObject())) ||
959           JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIException));
960   }
961   return NS_OK;
962 }
963 
964 /*******************************************************/
965 // JavaScript Constructor for nsIXPCConstructor objects (Components.Constructor)
966 
967 class nsXPCComponents_Constructor final : public nsIXPCComponents_Constructor,
968                                           public nsIXPCScriptable,
969                                           public nsIClassInfo {
970  public:
971   // all the interface method declarations...
972   NS_DECL_ISUPPORTS
973   NS_DECL_NSIXPCCOMPONENTS_CONSTRUCTOR
974   NS_DECL_NSIXPCSCRIPTABLE
975   NS_DECL_NSICLASSINFO
976 
977  public:
978   nsXPCComponents_Constructor();
979 
980  private:
981   virtual ~nsXPCComponents_Constructor();
982   static bool InnerConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
983   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
984                                   JSContext* cx, HandleObject obj,
985                                   const CallArgs& args, bool* _retval);
986 };
987 
988 /***************************************************************************/
989 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & aArray)990 nsXPCComponents_Constructor::GetInterfaces(nsTArray<nsIID>& aArray) {
991   aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Constructor),
992                            NS_GET_IID(nsIXPCScriptable)};
993   return NS_OK;
994 }
995 
996 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)997 nsXPCComponents_Constructor::GetScriptableHelper(nsIXPCScriptable** retval) {
998   *retval = nullptr;
999   return NS_OK;
1000 }
1001 
1002 NS_IMETHODIMP
GetContractID(nsACString & aContractID)1003 nsXPCComponents_Constructor::GetContractID(nsACString& aContractID) {
1004   aContractID.SetIsVoid(true);
1005   return NS_ERROR_NOT_AVAILABLE;
1006 }
1007 
1008 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)1009 nsXPCComponents_Constructor::GetClassDescription(
1010     nsACString& aClassDescription) {
1011   aClassDescription.AssignLiteral("XPCComponents_Constructor");
1012   return NS_OK;
1013 }
1014 
1015 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)1016 nsXPCComponents_Constructor::GetClassID(nsCID** aClassID) {
1017   *aClassID = nullptr;
1018   return NS_OK;
1019 }
1020 
1021 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)1022 nsXPCComponents_Constructor::GetFlags(uint32_t* aFlags) {
1023   *aFlags = 0;
1024   return NS_OK;
1025 }
1026 
1027 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)1028 nsXPCComponents_Constructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
1029   return NS_ERROR_NOT_AVAILABLE;
1030 }
1031 
1032 nsXPCComponents_Constructor::nsXPCComponents_Constructor() = default;
1033 
~nsXPCComponents_Constructor()1034 nsXPCComponents_Constructor::~nsXPCComponents_Constructor() {
1035   // empty
1036 }
1037 
NS_IMPL_ISUPPORTS(nsXPCComponents_Constructor,nsIXPCComponents_Constructor,nsIXPCScriptable,nsIClassInfo)1038 NS_IMPL_ISUPPORTS(nsXPCComponents_Constructor, nsIXPCComponents_Constructor,
1039                   nsIXPCScriptable, nsIClassInfo)
1040 
1041 // The nsIXPCScriptable map declaration that will generate stubs for us...
1042 #define XPC_MAP_CLASSNAME nsXPCComponents_Constructor
1043 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Constructor"
1044 #define XPC_MAP_FLAGS                                         \
1045   (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
1046    XPC_SCRIPTABLE_WANT_HASINSTANCE |                          \
1047    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
1048 #include "xpc_map_end.h" /* This will #undef the above */
1049 
1050 // static
1051 bool nsXPCComponents_Constructor::InnerConstructor(JSContext* cx, unsigned argc,
1052                                                    JS::Value* vp) {
1053   CallArgs args = CallArgsFromVp(argc, vp);
1054   RootedObject callee(cx, &args.callee());
1055 
1056   // Fetch the property name ids, so we can look them up.
1057   XPCJSRuntime* runtime = XPCJSRuntime::Get();
1058   HandleId classIDProp = runtime->GetStringID(XPCJSContext::IDX_CLASS_ID);
1059   HandleId interfaceIDProp =
1060       runtime->GetStringID(XPCJSContext::IDX_INTERFACE_ID);
1061   HandleId initializerProp =
1062       runtime->GetStringID(XPCJSContext::IDX_INITIALIZER);
1063 
1064   // Get properties ('classID', 'interfaceID', and 'initializer') off the
1065   // constructor object.
1066   RootedValue classIDv(cx);
1067   RootedValue interfaceID(cx);
1068   RootedValue initializer(cx);
1069   if (!JS_GetPropertyById(cx, callee, classIDProp, &classIDv) ||
1070       !JS_GetPropertyById(cx, callee, interfaceIDProp, &interfaceID) ||
1071       !JS_GetPropertyById(cx, callee, initializerProp, &initializer)) {
1072     return false;
1073   }
1074   if (!classIDv.isObject() || !interfaceID.isObject()) {
1075     XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx);
1076     return false;
1077   }
1078 
1079   // Call 'createInstance' on the 'classID' object to create the object.
1080   RootedValue instancev(cx);
1081   RootedObject classID(cx, &classIDv.toObject());
1082   if (!JS_CallFunctionName(cx, classID, "createInstance",
1083                            HandleValueArray(interfaceID), &instancev)) {
1084     return false;
1085   }
1086   if (!instancev.isObject()) {
1087     XPCThrower::Throw(NS_ERROR_FAILURE, cx);
1088     return false;
1089   }
1090 
1091   // Call the method 'initializer' on the instance, passing in our parameters.
1092   if (!initializer.isUndefined()) {
1093     RootedValue dummy(cx);
1094     RootedValue initfunc(cx);
1095     RootedId initid(cx);
1096     RootedObject instance(cx, &instancev.toObject());
1097     if (!JS_ValueToId(cx, initializer, &initid) ||
1098         !JS_GetPropertyById(cx, instance, initid, &initfunc) ||
1099         !JS_CallFunctionValue(cx, instance, initfunc, args, &dummy)) {
1100       return false;
1101     }
1102   }
1103 
1104   args.rval().set(instancev);
1105   return true;
1106 }
1107 
1108 NS_IMETHODIMP
Call(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)1109 nsXPCComponents_Constructor::Call(nsIXPConnectWrappedNative* wrapper,
1110                                   JSContext* cx, JSObject* objArg,
1111                                   const CallArgs& args, bool* _retval) {
1112   RootedObject obj(cx, objArg);
1113   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1114 }
1115 
1116 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)1117 nsXPCComponents_Constructor::Construct(nsIXPConnectWrappedNative* wrapper,
1118                                        JSContext* cx, JSObject* objArg,
1119                                        const CallArgs& args, bool* _retval) {
1120   RootedObject obj(cx, objArg);
1121   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1122 }
1123 
1124 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)1125 nsresult nsXPCComponents_Constructor::CallOrConstruct(
1126     nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj,
1127     const CallArgs& args, bool* _retval) {
1128   // make sure we have at least one arg
1129 
1130   if (args.length() < 1) {
1131     return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
1132   }
1133 
1134   // Fetch the property name ids, so we can look them up.
1135   XPCJSRuntime* runtime = XPCJSRuntime::Get();
1136   HandleId classIDProp = runtime->GetStringID(XPCJSContext::IDX_CLASS_ID);
1137   HandleId interfaceIDProp =
1138       runtime->GetStringID(XPCJSContext::IDX_INTERFACE_ID);
1139   HandleId initializerProp =
1140       runtime->GetStringID(XPCJSContext::IDX_INITIALIZER);
1141 
1142   // get the various other object pointers we need
1143 
1144   nsIXPConnect* xpc = nsIXPConnect::XPConnect();
1145   XPCWrappedNativeScope* scope = ObjectScope(obj);
1146   nsCOMPtr<nsIXPCComponents> comp;
1147 
1148   if (!xpc || !scope || !(comp = scope->GetComponents())) {
1149     return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1150   }
1151 
1152   // Prevent non-chrome code from creating constructor objects.
1153   if (!nsContentUtils::IsCallerChrome()) {
1154     return ThrowAndFail(NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED, cx, _retval);
1155   }
1156 
1157   JSFunction* ctorfn = JS_NewFunction(cx, InnerConstructor, 0,
1158                                       JSFUN_CONSTRUCTOR, "XPCOM_Constructor");
1159   if (!ctorfn) {
1160     return ThrowAndFail(NS_ERROR_OUT_OF_MEMORY, cx, _retval);
1161   }
1162 
1163   JS::RootedObject ctor(cx, JS_GetFunctionObject(ctorfn));
1164 
1165   if (args.length() >= 3) {
1166     // args[2] is an initializer function or property name
1167     RootedString str(cx, ToString(cx, args[2]));
1168     if (!JS_DefinePropertyById(
1169             cx, ctor, initializerProp, str,
1170             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
1171       return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
1172     }
1173   }
1174 
1175   RootedString ifaceName(cx);
1176   if (args.length() >= 2) {
1177     ifaceName = ToString(cx, args[1]);
1178   } else {
1179     ifaceName = JS_NewStringCopyZ(cx, "nsISupports");
1180   }
1181 
1182   if (!ifaceName) {
1183     return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1184   }
1185 
1186   // a new scope to avoid warnings about shadowed names
1187   {
1188     nsCOMPtr<nsIXPCComponents_Interfaces> ifaces;
1189     RootedObject ifacesObj(cx);
1190 
1191     // we do the lookup by asking the Components.interfaces object
1192     // for the property with this name - i.e. we let its caching of these
1193     // nsIJSIID objects work for us.
1194 
1195     if (NS_FAILED(comp->GetInterfaces(getter_AddRefs(ifaces))) ||
1196         NS_FAILED(xpc->WrapNative(cx, obj, ifaces,
1197                                   NS_GET_IID(nsIXPCComponents_Interfaces),
1198                                   ifacesObj.address())) ||
1199         !ifacesObj) {
1200       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1201     }
1202 
1203     RootedId id(cx);
1204     if (!JS_StringToId(cx, ifaceName, &id)) {
1205       return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1206     }
1207 
1208     RootedValue val(cx);
1209     if (!JS_GetPropertyById(cx, ifacesObj, id, &val) || val.isPrimitive()) {
1210       return ThrowAndFail(NS_ERROR_XPC_BAD_IID, cx, _retval);
1211     }
1212 
1213     if (!JS_DefinePropertyById(
1214             cx, ctor, interfaceIDProp, val,
1215             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
1216       return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
1217     }
1218   }
1219 
1220   // a new scope to avoid warnings about shadowed names
1221   {
1222     // argv[0] is a contractid name string
1223 
1224     // we do the lookup by asking the Components.classes object
1225     // for the property with this name - i.e. we let its caching of these
1226     // nsIJSCID objects work for us.
1227 
1228     nsCOMPtr<nsIXPCComponents_Classes> classes;
1229     RootedObject classesObj(cx);
1230 
1231     if (NS_FAILED(comp->GetClasses(getter_AddRefs(classes))) ||
1232         NS_FAILED(xpc->WrapNative(cx, obj, classes,
1233                                   NS_GET_IID(nsIXPCComponents_Classes),
1234                                   classesObj.address())) ||
1235         !classesObj) {
1236       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1237     }
1238 
1239     RootedString str(cx, ToString(cx, args[0]));
1240     RootedId id(cx);
1241     if (!str || !JS_StringToId(cx, str, &id)) {
1242       return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1243     }
1244 
1245     RootedValue val(cx);
1246     if (!JS_GetPropertyById(cx, classesObj, id, &val) || val.isPrimitive()) {
1247       return ThrowAndFail(NS_ERROR_XPC_BAD_CID, cx, _retval);
1248     }
1249 
1250     if (!JS_DefinePropertyById(
1251             cx, ctor, classIDProp, val,
1252             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
1253       return ThrowAndFail(NS_ERROR_FAILURE, cx, _retval);
1254     }
1255   }
1256 
1257   args.rval().setObject(*ctor);
1258   return NS_OK;
1259 }
1260 
1261 NS_IMETHODIMP
HasInstance(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,HandleValue val,bool * isa,bool * _retval)1262 nsXPCComponents_Constructor::HasInstance(nsIXPConnectWrappedNative* wrapper,
1263                                          JSContext* cx, JSObject* obj,
1264                                          HandleValue val, bool* isa,
1265                                          bool* _retval) {
1266   *isa =
1267       val.isObject() && JS_IsNativeFunction(&val.toObject(), InnerConstructor);
1268   return NS_OK;
1269 }
1270 
1271 class nsXPCComponents_Utils final : public nsIXPCComponents_Utils,
1272                                     public nsIXPCScriptable {
1273  public:
1274   // all the interface method declarations...
1275   NS_DECL_ISUPPORTS
1276   NS_DECL_NSIXPCSCRIPTABLE
1277   NS_DECL_NSIXPCCOMPONENTS_UTILS
1278 
1279  public:
1280   nsXPCComponents_Utils() = default;
1281 
1282  private:
1283   virtual ~nsXPCComponents_Utils() = default;
1284   nsCOMPtr<nsIXPCComponents_utils_Sandbox> mSandbox;
1285 };
1286 
NS_IMPL_ISUPPORTS(nsXPCComponents_Utils,nsIXPCComponents_Utils,nsIXPCScriptable)1287 NS_IMPL_ISUPPORTS(nsXPCComponents_Utils, nsIXPCComponents_Utils,
1288                   nsIXPCScriptable)
1289 
1290 // The nsIXPCScriptable map declaration that will generate stubs for us...
1291 #define XPC_MAP_CLASSNAME nsXPCComponents_Utils
1292 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Utils"
1293 #define XPC_MAP_FLAGS XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE
1294 #include "xpc_map_end.h" /* This will #undef the above */
1295 
1296 NS_IMETHODIMP
1297 nsXPCComponents_Utils::GetSandbox(nsIXPCComponents_utils_Sandbox** aSandbox) {
1298   NS_ENSURE_ARG_POINTER(aSandbox);
1299   if (!mSandbox) {
1300     mSandbox = NewSandboxConstructor();
1301   }
1302 
1303   nsCOMPtr<nsIXPCComponents_utils_Sandbox> rval = mSandbox;
1304   rval.forget(aSandbox);
1305   return NS_OK;
1306 }
1307 
1308 NS_IMETHODIMP
CreateServicesCache(JSContext * aCx,MutableHandleValue aServices)1309 nsXPCComponents_Utils::CreateServicesCache(JSContext* aCx,
1310                                            MutableHandleValue aServices) {
1311   if (JSObject* services = NewJSServices(aCx)) {
1312     aServices.setObject(*services);
1313     return NS_OK;
1314   }
1315   return NS_ERROR_FAILURE;
1316 }
1317 
1318 NS_IMETHODIMP
ReportError(HandleValue error,HandleValue stack,JSContext * cx)1319 nsXPCComponents_Utils::ReportError(HandleValue error, HandleValue stack,
1320                                    JSContext* cx) {
1321   // This function shall never fail! Silently eat any failure conditions.
1322 
1323   nsCOMPtr<nsIConsoleService> console(
1324       do_GetService(NS_CONSOLESERVICE_CONTRACTID));
1325   if (!console) {
1326     return NS_OK;
1327   }
1328 
1329   nsGlobalWindowInner* win = CurrentWindowOrNull(cx);
1330   const uint64_t innerWindowID = win ? win->WindowID() : 0;
1331 
1332   Rooted<Maybe<Value>> exception(cx, Some(error));
1333   if (!innerWindowID) {
1334     // Leak mitigation: nsConsoleService::ClearMessagesForWindowID needs
1335     // a WindowID for cleanup and exception values could hold arbitrary
1336     // objects alive.
1337     exception = Nothing();
1338   }
1339 
1340   nsCOMPtr<nsIScriptError> scripterr;
1341   RootedObject errorObj(cx, error.isObject() ? &error.toObject() : nullptr);
1342   if (errorObj) {
1343     JS::RootedObject stackVal(cx);
1344     JS::RootedObject stackGlobal(cx);
1345     FindExceptionStackForConsoleReport(win, error, nullptr, &stackVal,
1346                                        &stackGlobal);
1347     if (stackVal) {
1348       scripterr = CreateScriptError(win, exception, stackVal, stackGlobal);
1349     }
1350   }
1351 
1352   nsString fileName;
1353   uint32_t lineNo = 0;
1354 
1355   if (!scripterr) {
1356     RootedObject stackObj(cx);
1357     RootedObject stackGlobal(cx);
1358     if (stack.isObject()) {
1359       if (!JS::IsMaybeWrappedSavedFrame(&stack.toObject())) {
1360         return NS_ERROR_INVALID_ARG;
1361       }
1362 
1363       // |stack| might be a wrapper, but it must be same-compartment with
1364       // the current global.
1365       stackObj = &stack.toObject();
1366       stackGlobal = JS::CurrentGlobalOrNull(cx);
1367       js::AssertSameCompartment(stackObj, stackGlobal);
1368 
1369       JSPrincipals* principals =
1370           JS::GetRealmPrincipals(js::GetContextRealm(cx));
1371 
1372       if (GetSavedFrameLine(cx, principals, stackObj, &lineNo) !=
1373           SavedFrameResult::Ok) {
1374         JS_ClearPendingException(cx);
1375       }
1376 
1377       RootedString source(cx);
1378       nsAutoJSString str;
1379       if (GetSavedFrameSource(cx, principals, stackObj, &source) ==
1380               SavedFrameResult::Ok &&
1381           str.init(cx, source)) {
1382         fileName = str;
1383       } else {
1384         JS_ClearPendingException(cx);
1385       }
1386     } else {
1387       nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
1388       if (frame) {
1389         frame->GetFilename(cx, fileName);
1390         lineNo = frame->GetLineNumber(cx);
1391         JS::Rooted<JS::Value> stack(cx);
1392         nsresult rv = frame->GetNativeSavedFrame(&stack);
1393         if (NS_SUCCEEDED(rv) && stack.isObject()) {
1394           stackObj = &stack.toObject();
1395           MOZ_ASSERT(JS::IsUnwrappedSavedFrame(stackObj));
1396           stackGlobal = JS::GetNonCCWObjectGlobal(stackObj);
1397         }
1398       }
1399     }
1400 
1401     if (stackObj) {
1402       scripterr = CreateScriptError(win, exception, stackObj, stackGlobal);
1403     }
1404   }
1405 
1406   if (!scripterr) {
1407     scripterr = CreateScriptError(win, exception, nullptr, nullptr);
1408   }
1409 
1410   JSErrorReport* err = errorObj ? JS_ErrorFromException(cx, errorObj) : nullptr;
1411   if (err) {
1412     // It's a proper JS Error
1413     nsAutoString fileUni;
1414     CopyUTF8toUTF16(mozilla::MakeStringSpan(err->filename), fileUni);
1415 
1416     uint32_t column = err->tokenOffset();
1417 
1418     const char16_t* linebuf = err->linebuf();
1419     uint32_t flags = err->isWarning() ? nsIScriptError::warningFlag
1420                                       : nsIScriptError::errorFlag;
1421 
1422     nsresult rv = scripterr->InitWithWindowID(
1423         err->message() ? NS_ConvertUTF8toUTF16(err->message().c_str())
1424                        : EmptyString(),
1425         fileUni,
1426         linebuf ? nsDependentString(linebuf, err->linebufLength())
1427                 : EmptyString(),
1428         err->lineno, column, flags, "XPConnect JavaScript", innerWindowID,
1429         innerWindowID == 0 ? true : false);
1430     NS_ENSURE_SUCCESS(rv, NS_OK);
1431 
1432     console->LogMessage(scripterr);
1433     return NS_OK;
1434   }
1435 
1436   // It's not a JS Error object, so we synthesize as best we're able.
1437   RootedString msgstr(cx, ToString(cx, error));
1438   if (!msgstr) {
1439     return NS_OK;
1440   }
1441 
1442   nsAutoJSString msg;
1443   if (!msg.init(cx, msgstr)) {
1444     return NS_OK;
1445   }
1446 
1447   nsresult rv = scripterr->InitWithWindowID(
1448       msg, fileName, u""_ns, lineNo, 0, 0, "XPConnect JavaScript",
1449       innerWindowID, innerWindowID == 0 ? true : false);
1450   NS_ENSURE_SUCCESS(rv, NS_OK);
1451 
1452   console->LogMessage(scripterr);
1453   return NS_OK;
1454 }
1455 
1456 NS_IMETHODIMP
EvalInSandbox(const nsAString & source,HandleValue sandboxVal,HandleValue version,const nsACString & filenameArg,int32_t lineNumber,bool enforceFilenameRestrictions,JSContext * cx,uint8_t optionalArgc,MutableHandleValue retval)1457 nsXPCComponents_Utils::EvalInSandbox(
1458     const nsAString& source, HandleValue sandboxVal, HandleValue version,
1459     const nsACString& filenameArg, int32_t lineNumber,
1460     bool enforceFilenameRestrictions, JSContext* cx, uint8_t optionalArgc,
1461     MutableHandleValue retval) {
1462   RootedObject sandbox(cx);
1463   if (!JS_ValueToObject(cx, sandboxVal, &sandbox) || !sandbox) {
1464     return NS_ERROR_INVALID_ARG;
1465   }
1466 
1467   // Optional third argument: JS version, as a string, is unused.
1468 
1469   // Optional fourth and fifth arguments: filename and line number.
1470   int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 1;
1471   nsCString filename;
1472   if (!filenameArg.IsVoid()) {
1473     filename.Assign(filenameArg);
1474   } else {
1475     // Get the current source info.
1476     nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
1477     if (frame) {
1478       nsString frameFile;
1479       frame->GetFilename(cx, frameFile);
1480       CopyUTF16toUTF8(frameFile, filename);
1481       lineNo = frame->GetLineNumber(cx);
1482     }
1483   }
1484   enforceFilenameRestrictions =
1485       (optionalArgc >= 4) ? enforceFilenameRestrictions : true;
1486 
1487   return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo,
1488                             enforceFilenameRestrictions, retval);
1489 }
1490 
1491 NS_IMETHODIMP
GetUAWidgetScope(nsIPrincipal * principal,JSContext * cx,MutableHandleValue rval)1492 nsXPCComponents_Utils::GetUAWidgetScope(nsIPrincipal* principal, JSContext* cx,
1493                                         MutableHandleValue rval) {
1494   rval.set(UndefinedValue());
1495 
1496   JSObject* scope = xpc::GetUAWidgetScope(cx, principal);
1497 
1498   rval.set(JS::ObjectValue(*scope));
1499 
1500   return NS_OK;
1501 }
1502 
1503 NS_IMETHODIMP
GetSandboxMetadata(HandleValue sandboxVal,JSContext * cx,MutableHandleValue rval)1504 nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal, JSContext* cx,
1505                                           MutableHandleValue rval) {
1506   if (!sandboxVal.isObject()) {
1507     return NS_ERROR_INVALID_ARG;
1508   }
1509 
1510   RootedObject sandbox(cx, &sandboxVal.toObject());
1511   // We only care about sandboxes here, so CheckedUnwrapStatic is fine.
1512   sandbox = js::CheckedUnwrapStatic(sandbox);
1513   if (!sandbox || !xpc::IsSandbox(sandbox)) {
1514     return NS_ERROR_INVALID_ARG;
1515   }
1516 
1517   return xpc::GetSandboxMetadata(cx, sandbox, rval);
1518 }
1519 
1520 NS_IMETHODIMP
SetSandboxMetadata(HandleValue sandboxVal,HandleValue metadataVal,JSContext * cx)1521 nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal,
1522                                           HandleValue metadataVal,
1523                                           JSContext* cx) {
1524   if (!sandboxVal.isObject()) {
1525     return NS_ERROR_INVALID_ARG;
1526   }
1527 
1528   RootedObject sandbox(cx, &sandboxVal.toObject());
1529   // We only care about sandboxes here, so CheckedUnwrapStatic is fine.
1530   sandbox = js::CheckedUnwrapStatic(sandbox);
1531   if (!sandbox || !xpc::IsSandbox(sandbox)) {
1532     return NS_ERROR_INVALID_ARG;
1533   }
1534 
1535   nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadataVal);
1536   NS_ENSURE_SUCCESS(rv, rv);
1537 
1538   return NS_OK;
1539 }
1540 
1541 NS_IMETHODIMP
Import(const nsACString & registryLocation,HandleValue targetObj,JSContext * cx,uint8_t optionalArgc,MutableHandleValue retval)1542 nsXPCComponents_Utils::Import(const nsACString& registryLocation,
1543                               HandleValue targetObj, JSContext* cx,
1544                               uint8_t optionalArgc, MutableHandleValue retval) {
1545   RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
1546   MOZ_ASSERT(moduleloader);
1547 
1548   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("nsXPCComponents_Utils::Import", OTHER,
1549                                         registryLocation);
1550 
1551   return moduleloader->ImportInto(registryLocation, targetObj, cx, optionalArgc,
1552                                   retval);
1553 }
1554 
1555 NS_IMETHODIMP
IsModuleLoaded(const nsACString & registryLocation,bool * retval)1556 nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation,
1557                                       bool* retval) {
1558   RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
1559   MOZ_ASSERT(moduleloader);
1560   return moduleloader->IsModuleLoaded(registryLocation, retval);
1561 }
1562 
1563 NS_IMETHODIMP
Unload(const nsACString & registryLocation)1564 nsXPCComponents_Utils::Unload(const nsACString& registryLocation) {
1565   RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
1566   MOZ_ASSERT(moduleloader);
1567   return moduleloader->Unload(registryLocation);
1568 }
1569 
1570 NS_IMETHODIMP
ImportGlobalProperties(HandleValue aPropertyList,JSContext * cx)1571 nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList,
1572                                               JSContext* cx) {
1573   // Ensure we're working in the scripted caller's realm. This is not guaranteed
1574   // to be the current realm because we switch realms when calling cross-realm
1575   // functions.
1576   RootedObject global(cx, JS::GetScriptedCallerGlobal(cx));
1577   MOZ_ASSERT(global);
1578   js::AssertSameCompartment(cx, global);
1579   JSAutoRealm ar(cx, global);
1580 
1581   // Don't allow doing this if the global is a Window.
1582   nsGlobalWindowInner* win;
1583   if (NS_SUCCEEDED(UNWRAP_NON_WRAPPER_OBJECT(Window, global, win))) {
1584     return NS_ERROR_NOT_AVAILABLE;
1585   }
1586 
1587   GlobalProperties options;
1588   NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG);
1589 
1590   RootedObject propertyList(cx, &aPropertyList.toObject());
1591   bool isArray;
1592   if (NS_WARN_IF(!JS::IsArrayObject(cx, propertyList, &isArray))) {
1593     return NS_ERROR_FAILURE;
1594   }
1595   if (NS_WARN_IF(!isArray)) {
1596     return NS_ERROR_INVALID_ARG;
1597   }
1598 
1599   if (!options.Parse(cx, propertyList) ||
1600       !options.DefineInXPCComponents(cx, global)) {
1601     return NS_ERROR_FAILURE;
1602   }
1603 
1604   return NS_OK;
1605 }
1606 
1607 NS_IMETHODIMP
GetWeakReference(HandleValue object,JSContext * cx,xpcIJSWeakReference ** _retval)1608 nsXPCComponents_Utils::GetWeakReference(HandleValue object, JSContext* cx,
1609                                         xpcIJSWeakReference** _retval) {
1610   RefPtr<xpcJSWeakReference> ref = new xpcJSWeakReference();
1611   nsresult rv = ref->Init(cx, object);
1612   NS_ENSURE_SUCCESS(rv, rv);
1613   ref.forget(_retval);
1614   return NS_OK;
1615 }
1616 
1617 NS_IMETHODIMP
ForceGC(JSContext * aCx)1618 nsXPCComponents_Utils::ForceGC(JSContext* aCx) {
1619   PrepareForFullGC(aCx);
1620   NonIncrementalGC(aCx, GCOptions::Normal, GCReason::COMPONENT_UTILS);
1621   return NS_OK;
1622 }
1623 
1624 NS_IMETHODIMP
ForceCC(nsICycleCollectorListener * listener)1625 nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) {
1626   nsJSContext::CycleCollectNow(listener);
1627   return NS_OK;
1628 }
1629 
1630 NS_IMETHODIMP
CreateCCLogger(nsICycleCollectorListener ** aListener)1631 nsXPCComponents_Utils::CreateCCLogger(nsICycleCollectorListener** aListener) {
1632   NS_ENSURE_ARG_POINTER(aListener);
1633   nsCOMPtr<nsICycleCollectorListener> logger = nsCycleCollector_createLogger();
1634   logger.forget(aListener);
1635   return NS_OK;
1636 }
1637 
1638 NS_IMETHODIMP
FinishCC()1639 nsXPCComponents_Utils::FinishCC() {
1640   nsCycleCollector_finishAnyCurrentCollection();
1641   return NS_OK;
1642 }
1643 
1644 NS_IMETHODIMP
CcSlice(int64_t budget)1645 nsXPCComponents_Utils::CcSlice(int64_t budget) {
1646   nsJSContext::RunCycleCollectorWorkSlice(budget);
1647   return NS_OK;
1648 }
1649 
1650 NS_IMETHODIMP
GetMaxCCSliceTimeSinceClear(int32_t * out)1651 nsXPCComponents_Utils::GetMaxCCSliceTimeSinceClear(int32_t* out) {
1652   *out = nsJSContext::GetMaxCCSliceTimeSinceClear();
1653   return NS_OK;
1654 }
1655 
1656 NS_IMETHODIMP
ClearMaxCCTime()1657 nsXPCComponents_Utils::ClearMaxCCTime() {
1658   nsJSContext::ClearMaxCCSliceTime();
1659   return NS_OK;
1660 }
1661 
1662 NS_IMETHODIMP
ForceShrinkingGC(JSContext * aCx)1663 nsXPCComponents_Utils::ForceShrinkingGC(JSContext* aCx) {
1664   PrepareForFullGC(aCx);
1665   NonIncrementalGC(aCx, GCOptions::Shrink, GCReason::COMPONENT_UTILS);
1666   return NS_OK;
1667 }
1668 
1669 class PreciseGCRunnable : public Runnable {
1670  public:
PreciseGCRunnable(nsIScheduledGCCallback * aCallback,bool aShrinking)1671   PreciseGCRunnable(nsIScheduledGCCallback* aCallback, bool aShrinking)
1672       : mozilla::Runnable("PreciseGCRunnable"),
1673         mCallback(aCallback),
1674         mShrinking(aShrinking) {}
1675 
Run()1676   NS_IMETHOD Run() override {
1677     nsJSContext::GarbageCollectNow(
1678         GCReason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC,
1679         mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC);
1680 
1681     mCallback->Callback();
1682     return NS_OK;
1683   }
1684 
1685  private:
1686   nsCOMPtr<nsIScheduledGCCallback> mCallback;
1687   bool mShrinking;
1688 };
1689 
1690 NS_IMETHODIMP
SchedulePreciseGC(nsIScheduledGCCallback * aCallback)1691 nsXPCComponents_Utils::SchedulePreciseGC(nsIScheduledGCCallback* aCallback) {
1692   RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, false);
1693   return NS_DispatchToMainThread(event);
1694 }
1695 
1696 NS_IMETHODIMP
SchedulePreciseShrinkingGC(nsIScheduledGCCallback * aCallback)1697 nsXPCComponents_Utils::SchedulePreciseShrinkingGC(
1698     nsIScheduledGCCallback* aCallback) {
1699   RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, true);
1700   return NS_DispatchToMainThread(event);
1701 }
1702 
1703 NS_IMETHODIMP
UnlinkGhostWindows()1704 nsXPCComponents_Utils::UnlinkGhostWindows() {
1705 #ifdef DEBUG
1706   nsWindowMemoryReporter::UnlinkGhostWindows();
1707 
1708   if (XRE_IsParentProcess()) {
1709     nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
1710     if (obsvc) {
1711       obsvc->NotifyObservers(nullptr, "child-ghost-request", nullptr);
1712     }
1713   }
1714 
1715   return NS_OK;
1716 #else
1717   return NS_ERROR_NOT_IMPLEMENTED;
1718 #endif
1719 }
1720 
1721 #ifdef NS_FREE_PERMANENT_DATA
1722 struct IntentionallyLeakedObject {
1723   MOZ_COUNTED_DEFAULT_CTOR(IntentionallyLeakedObject)
1724 
1725   MOZ_COUNTED_DTOR(IntentionallyLeakedObject)
1726 };
1727 #endif
1728 
1729 NS_IMETHODIMP
IntentionallyLeak()1730 nsXPCComponents_Utils::IntentionallyLeak() {
1731 #ifdef NS_FREE_PERMANENT_DATA
1732   Unused << new IntentionallyLeakedObject();
1733   return NS_OK;
1734 #else
1735   return NS_ERROR_NOT_IMPLEMENTED;
1736 #endif
1737 }
1738 
1739 NS_IMETHODIMP
GetJSTestingFunctions(JSContext * cx,MutableHandleValue retval)1740 nsXPCComponents_Utils::GetJSTestingFunctions(JSContext* cx,
1741                                              MutableHandleValue retval) {
1742   JSObject* obj = js::GetTestingFunctions(cx);
1743   if (!obj) {
1744     return NS_ERROR_XPC_JAVASCRIPT_ERROR;
1745   }
1746   retval.setObject(*obj);
1747   return NS_OK;
1748 }
1749 
1750 NS_IMETHODIMP
GetFunctionSourceLocation(HandleValue funcValue,JSContext * cx,MutableHandleValue retval)1751 nsXPCComponents_Utils::GetFunctionSourceLocation(HandleValue funcValue,
1752                                                  JSContext* cx,
1753                                                  MutableHandleValue retval) {
1754   NS_ENSURE_TRUE(funcValue.isObject(), NS_ERROR_INVALID_ARG);
1755 
1756   nsAutoString filename;
1757   uint32_t lineNumber;
1758   {
1759     RootedObject funcObj(cx, UncheckedUnwrap(&funcValue.toObject()));
1760     JSAutoRealm ar(cx, funcObj);
1761 
1762     Rooted<JSFunction*> func(cx, JS_GetObjectFunction(funcObj));
1763     NS_ENSURE_TRUE(func, NS_ERROR_INVALID_ARG);
1764 
1765     RootedScript script(cx, JS_GetFunctionScript(cx, func));
1766     NS_ENSURE_TRUE(func, NS_ERROR_FAILURE);
1767 
1768     AppendUTF8toUTF16(nsDependentCString(JS_GetScriptFilename(script)),
1769                       filename);
1770     lineNumber = JS_GetScriptBaseLineNumber(cx, script) + 1;
1771   }
1772 
1773   RootedObject res(cx, JS_NewPlainObject(cx));
1774   NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY);
1775 
1776   RootedValue filenameVal(cx);
1777   if (!xpc::NonVoidStringToJsval(cx, filename, &filenameVal) ||
1778       !JS_DefineProperty(cx, res, "filename", filenameVal, JSPROP_ENUMERATE)) {
1779     return NS_ERROR_OUT_OF_MEMORY;
1780   }
1781 
1782   if (!JS_DefineProperty(cx, res, "lineNumber", lineNumber, JSPROP_ENUMERATE)) {
1783     return NS_ERROR_OUT_OF_MEMORY;
1784   }
1785 
1786   retval.setObject(*res);
1787   return NS_OK;
1788 }
1789 
1790 NS_IMETHODIMP
CallFunctionWithAsyncStack(HandleValue function,nsIStackFrame * stack,const nsAString & asyncCause,JSContext * cx,MutableHandleValue retval)1791 nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function,
1792                                                   nsIStackFrame* stack,
1793                                                   const nsAString& asyncCause,
1794                                                   JSContext* cx,
1795                                                   MutableHandleValue retval) {
1796   nsresult rv;
1797 
1798   if (!stack || asyncCause.IsEmpty()) {
1799     return NS_ERROR_INVALID_ARG;
1800   }
1801 
1802   JS::Rooted<JS::Value> asyncStack(cx);
1803   rv = stack->GetNativeSavedFrame(&asyncStack);
1804   if (NS_FAILED(rv)) {
1805     return rv;
1806   }
1807   if (!asyncStack.isObject()) {
1808     JS_ReportErrorASCII(cx, "Must use a native JavaScript stack frame");
1809     return NS_ERROR_INVALID_ARG;
1810   }
1811 
1812   JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject());
1813 
1814   NS_ConvertUTF16toUTF8 utf8Cause(asyncCause);
1815   JS::AutoSetAsyncStackForNewCalls sas(
1816       cx, asyncStackObj, utf8Cause.get(),
1817       JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT);
1818 
1819   if (!JS_CallFunctionValue(cx, nullptr, function,
1820                             JS::HandleValueArray::empty(), retval)) {
1821     return NS_ERROR_XPC_JAVASCRIPT_ERROR;
1822   }
1823 
1824   return NS_OK;
1825 }
1826 
1827 NS_IMETHODIMP
GetGlobalForObject(HandleValue object,JSContext * cx,MutableHandleValue retval)1828 nsXPCComponents_Utils::GetGlobalForObject(HandleValue object, JSContext* cx,
1829                                           MutableHandleValue retval) {
1830   // First argument must be an object.
1831   if (object.isPrimitive()) {
1832     return NS_ERROR_XPC_BAD_CONVERT_JS;
1833   }
1834 
1835   // When getting the global for a cross-compartment wrapper, we really want
1836   // a wrapper for the foreign global. So we need to unwrap before getting the
1837   // global and then wrap the result.
1838   Rooted<JSObject*> obj(cx, &object.toObject());
1839   obj = JS::GetNonCCWObjectGlobal(js::UncheckedUnwrap(obj));
1840 
1841   if (!JS_WrapObject(cx, &obj)) {
1842     return NS_ERROR_FAILURE;
1843   }
1844 
1845   // Get the WindowProxy if necessary.
1846   obj = js::ToWindowProxyIfWindow(obj);
1847 
1848   retval.setObject(*obj);
1849   return NS_OK;
1850 }
1851 
1852 NS_IMETHODIMP
IsProxy(HandleValue vobj,JSContext * cx,bool * rval)1853 nsXPCComponents_Utils::IsProxy(HandleValue vobj, JSContext* cx, bool* rval) {
1854   if (!vobj.isObject()) {
1855     *rval = false;
1856     return NS_OK;
1857   }
1858 
1859   RootedObject obj(cx, &vobj.toObject());
1860   // We need to do a dynamic unwrap, because we apparently want to treat
1861   // "failure to unwrap" differently from "not a proxy" (throw for the former,
1862   // return false for the latter).
1863   obj = js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
1864   NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
1865 
1866   *rval = js::IsScriptedProxy(obj);
1867   return NS_OK;
1868 }
1869 
1870 NS_IMETHODIMP
ExportFunction(HandleValue vfunction,HandleValue vscope,HandleValue voptions,JSContext * cx,MutableHandleValue rval)1871 nsXPCComponents_Utils::ExportFunction(HandleValue vfunction, HandleValue vscope,
1872                                       HandleValue voptions, JSContext* cx,
1873                                       MutableHandleValue rval) {
1874   if (!xpc::ExportFunction(cx, vfunction, vscope, voptions, rval)) {
1875     return NS_ERROR_FAILURE;
1876   }
1877   return NS_OK;
1878 }
1879 
1880 NS_IMETHODIMP
CreateObjectIn(HandleValue vobj,HandleValue voptions,JSContext * cx,MutableHandleValue rval)1881 nsXPCComponents_Utils::CreateObjectIn(HandleValue vobj, HandleValue voptions,
1882                                       JSContext* cx, MutableHandleValue rval) {
1883   RootedObject optionsObject(
1884       cx, voptions.isObject() ? &voptions.toObject() : nullptr);
1885   CreateObjectInOptions options(cx, optionsObject);
1886   if (voptions.isObject() && !options.Parse()) {
1887     return NS_ERROR_FAILURE;
1888   }
1889 
1890   if (!xpc::CreateObjectIn(cx, vobj, options, rval)) {
1891     return NS_ERROR_FAILURE;
1892   }
1893   return NS_OK;
1894 }
1895 
1896 NS_IMETHODIMP
MakeObjectPropsNormal(HandleValue vobj,JSContext * cx)1897 nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext* cx) {
1898   if (!cx) {
1899     return NS_ERROR_FAILURE;
1900   }
1901 
1902   // first argument must be an object
1903   if (vobj.isPrimitive()) {
1904     return NS_ERROR_XPC_BAD_CONVERT_JS;
1905   }
1906 
1907   RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject()));
1908   JSAutoRealm ar(cx, obj);
1909   Rooted<IdVector> ida(cx, IdVector(cx));
1910   if (!JS_Enumerate(cx, obj, &ida)) {
1911     return NS_ERROR_FAILURE;
1912   }
1913 
1914   RootedId id(cx);
1915   RootedValue v(cx);
1916   for (size_t i = 0; i < ida.length(); ++i) {
1917     id = ida[i];
1918 
1919     if (!JS_GetPropertyById(cx, obj, id, &v)) {
1920       return NS_ERROR_FAILURE;
1921     }
1922 
1923     if (v.isPrimitive()) {
1924       continue;
1925     }
1926 
1927     RootedObject propobj(cx, &v.toObject());
1928     // TODO Deal with non-functions.
1929     if (!js::IsWrapper(propobj) || !JS::IsCallable(propobj)) {
1930       continue;
1931     }
1932 
1933     FunctionForwarderOptions forwarderOptions;
1934     if (!NewFunctionForwarder(cx, id, propobj, forwarderOptions, &v) ||
1935         !JS_SetPropertyById(cx, obj, id, v))
1936       return NS_ERROR_FAILURE;
1937   }
1938 
1939   return NS_OK;
1940 }
1941 
1942 NS_IMETHODIMP
IsDeadWrapper(HandleValue obj,bool * out)1943 nsXPCComponents_Utils::IsDeadWrapper(HandleValue obj, bool* out) {
1944   *out = false;
1945   if (obj.isPrimitive()) {
1946     return NS_ERROR_INVALID_ARG;
1947   }
1948 
1949   // We should never have cross-compartment wrappers for dead wrappers.
1950   MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(&obj.toObject()),
1951                 !JS_IsDeadWrapper(js::UncheckedUnwrap(&obj.toObject())));
1952 
1953   *out = JS_IsDeadWrapper(&obj.toObject());
1954   return NS_OK;
1955 }
1956 
1957 NS_IMETHODIMP
IsRemoteProxy(HandleValue val,bool * out)1958 nsXPCComponents_Utils::IsRemoteProxy(HandleValue val, bool* out) {
1959   if (val.isObject()) {
1960     *out = dom::IsRemoteObjectProxy(UncheckedUnwrap(&val.toObject()));
1961     ;
1962   } else {
1963     *out = false;
1964   }
1965   return NS_OK;
1966 }
1967 
1968 NS_IMETHODIMP
RecomputeWrappers(HandleValue vobj,JSContext * cx)1969 nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext* cx) {
1970   // Determine the compartment of the given object, if any.
1971   JS::Compartment* c =
1972       vobj.isObject()
1973           ? JS::GetCompartment(js::UncheckedUnwrap(&vobj.toObject()))
1974           : nullptr;
1975 
1976   // If no compartment was given, recompute all.
1977   if (!c) {
1978     js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments());
1979     // Otherwise, recompute wrappers for the given compartment.
1980   } else {
1981     js::RecomputeWrappers(cx, js::SingleCompartment(c),
1982                           js::AllCompartments()) &&
1983         js::RecomputeWrappers(cx, js::AllCompartments(),
1984                               js::SingleCompartment(c));
1985   }
1986 
1987   return NS_OK;
1988 }
1989 
1990 NS_IMETHODIMP
SetWantXrays(HandleValue vscope,JSContext * cx)1991 nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx) {
1992   if (!vscope.isObject()) {
1993     return NS_ERROR_INVALID_ARG;
1994   }
1995   JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
1996   MOZ_RELEASE_ASSERT(!AccessCheck::isChrome(scopeObj),
1997                      "Don't call setWantXrays on system-principal scopes");
1998   JS::Compartment* compartment = JS::GetCompartment(scopeObj);
1999   CompartmentPrivate::Get(scopeObj)->wantXrays = true;
2000   bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
2001                                   js::AllCompartments());
2002   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
2003   return NS_OK;
2004 }
2005 
2006 NS_IMETHODIMP
Dispatch(HandleValue runnableArg,HandleValue scope,JSContext * cx)2007 nsXPCComponents_Utils::Dispatch(HandleValue runnableArg, HandleValue scope,
2008                                 JSContext* cx) {
2009   RootedValue runnable(cx, runnableArg);
2010   // Enter the given realm, if any, and rewrap runnable.
2011   Maybe<JSAutoRealm> ar;
2012   if (scope.isObject()) {
2013     JSObject* scopeObj = js::UncheckedUnwrap(&scope.toObject());
2014     if (!scopeObj) {
2015       return NS_ERROR_FAILURE;
2016     }
2017     ar.emplace(cx, scopeObj);
2018     if (!JS_WrapValue(cx, &runnable)) {
2019       return NS_ERROR_FAILURE;
2020     }
2021   }
2022 
2023   // Get an XPCWrappedJS for |runnable|.
2024   if (!runnable.isObject()) {
2025     return NS_ERROR_INVALID_ARG;
2026   }
2027 
2028   RootedObject runnableObj(cx, &runnable.toObject());
2029   nsCOMPtr<nsIRunnable> run;
2030   nsresult rv = nsXPConnect::XPConnect()->WrapJS(
2031       cx, runnableObj, NS_GET_IID(nsIRunnable), getter_AddRefs(run));
2032   NS_ENSURE_SUCCESS(rv, rv);
2033   MOZ_ASSERT(run);
2034 
2035   // Dispatch.
2036   return NS_DispatchToMainThread(run);
2037 }
2038 
2039 #define GENERATE_JSCONTEXTOPTION_GETTER_SETTER(_attr, _getter, _setter) \
2040   NS_IMETHODIMP                                                         \
2041   nsXPCComponents_Utils::Get##_attr(JSContext* cx, bool* aValue) {      \
2042     *aValue = ContextOptionsRef(cx)._getter();                          \
2043     return NS_OK;                                                       \
2044   }                                                                     \
2045   NS_IMETHODIMP                                                         \
2046   nsXPCComponents_Utils::Set##_attr(JSContext* cx, bool aValue) {       \
2047     ContextOptionsRef(cx)._setter(aValue);                              \
2048     return NS_OK;                                                       \
2049   }
2050 
GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict_mode,strictMode,setStrictMode)2051 GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict_mode, strictMode, setStrictMode)
2052 
2053 #undef GENERATE_JSCONTEXTOPTION_GETTER_SETTER
2054 
2055 NS_IMETHODIMP
2056 nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx) {
2057 #ifdef JS_GC_ZEAL
2058   JS_SetGCZeal(cx, uint8_t(aValue), JS_DEFAULT_ZEAL_FREQ);
2059 #endif
2060   return NS_OK;
2061 }
2062 
2063 NS_IMETHODIMP
GetIsInAutomation(bool * aResult)2064 nsXPCComponents_Utils::GetIsInAutomation(bool* aResult) {
2065   NS_ENSURE_ARG_POINTER(aResult);
2066 
2067   *aResult = xpc::IsInAutomation();
2068   return NS_OK;
2069 }
2070 
2071 NS_IMETHODIMP
ExitIfInAutomation()2072 nsXPCComponents_Utils::ExitIfInAutomation() {
2073   NS_ENSURE_TRUE(xpc::IsInAutomation(), NS_ERROR_FAILURE);
2074 
2075 #ifdef MOZ_GECKO_PROFILER
2076   profiler_shutdown(IsFastShutdown::Yes);
2077 #endif
2078 
2079   mozilla::AppShutdown::DoImmediateExit();
2080   return NS_OK;
2081 }
2082 
2083 NS_IMETHODIMP
CrashIfNotInAutomation()2084 nsXPCComponents_Utils::CrashIfNotInAutomation() {
2085   xpc::CrashIfNotInAutomation();
2086   return NS_OK;
2087 }
2088 
2089 NS_IMETHODIMP
NukeSandbox(HandleValue obj,JSContext * cx)2090 nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) {
2091   AUTO_PROFILER_LABEL("nsXPCComponents_Utils::NukeSandbox", OTHER);
2092   NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG);
2093   JSObject* wrapper = &obj.toObject();
2094   NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG);
2095   RootedObject sb(cx, UncheckedUnwrap(wrapper));
2096   NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG);
2097 
2098   xpc::NukeAllWrappersForRealm(cx, GetNonCCWObjectRealm(sb));
2099 
2100   return NS_OK;
2101 }
2102 
2103 NS_IMETHODIMP
BlockScriptForGlobal(HandleValue globalArg,JSContext * cx)2104 nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg,
2105                                             JSContext* cx) {
2106   NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
2107   RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
2108                                           /* stopAtWindowProxy = */ false));
2109   NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
2110   if (xpc::GetObjectPrincipal(global)->IsSystemPrincipal()) {
2111     JS_ReportErrorASCII(cx, "Script may not be disabled for system globals");
2112     return NS_ERROR_FAILURE;
2113   }
2114   Scriptability::Get(global).Block();
2115   return NS_OK;
2116 }
2117 
2118 NS_IMETHODIMP
UnblockScriptForGlobal(HandleValue globalArg,JSContext * cx)2119 nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg,
2120                                               JSContext* cx) {
2121   NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
2122   RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
2123                                           /* stopAtWindowProxy = */ false));
2124   NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
2125   if (xpc::GetObjectPrincipal(global)->IsSystemPrincipal()) {
2126     JS_ReportErrorASCII(cx, "Script may not be disabled for system globals");
2127     return NS_ERROR_FAILURE;
2128   }
2129   Scriptability::Get(global).Unblock();
2130   return NS_OK;
2131 }
2132 
2133 NS_IMETHODIMP
IsOpaqueWrapper(HandleValue obj,bool * aRetval)2134 nsXPCComponents_Utils::IsOpaqueWrapper(HandleValue obj, bool* aRetval) {
2135   *aRetval =
2136       obj.isObject() && xpc::WrapperFactory::IsOpaqueWrapper(&obj.toObject());
2137   return NS_OK;
2138 }
2139 
2140 NS_IMETHODIMP
IsXrayWrapper(HandleValue obj,bool * aRetval)2141 nsXPCComponents_Utils::IsXrayWrapper(HandleValue obj, bool* aRetval) {
2142   *aRetval =
2143       obj.isObject() && xpc::WrapperFactory::IsXrayWrapper(&obj.toObject());
2144   return NS_OK;
2145 }
2146 
2147 NS_IMETHODIMP
WaiveXrays(HandleValue aVal,JSContext * aCx,MutableHandleValue aRetval)2148 nsXPCComponents_Utils::WaiveXrays(HandleValue aVal, JSContext* aCx,
2149                                   MutableHandleValue aRetval) {
2150   RootedValue value(aCx, aVal);
2151   if (!xpc::WrapperFactory::WaiveXrayAndWrap(aCx, &value)) {
2152     return NS_ERROR_FAILURE;
2153   }
2154   aRetval.set(value);
2155   return NS_OK;
2156 }
2157 
2158 NS_IMETHODIMP
UnwaiveXrays(HandleValue aVal,JSContext * aCx,MutableHandleValue aRetval)2159 nsXPCComponents_Utils::UnwaiveXrays(HandleValue aVal, JSContext* aCx,
2160                                     MutableHandleValue aRetval) {
2161   if (!aVal.isObject()) {
2162     aRetval.set(aVal);
2163     return NS_OK;
2164   }
2165 
2166   RootedObject obj(aCx, js::UncheckedUnwrap(&aVal.toObject()));
2167   if (!JS_WrapObject(aCx, &obj)) {
2168     return NS_ERROR_FAILURE;
2169   }
2170   aRetval.setObject(*obj);
2171   return NS_OK;
2172 }
2173 
2174 NS_IMETHODIMP
GetClassName(HandleValue aObj,bool aUnwrap,JSContext * aCx,char ** aRv)2175 nsXPCComponents_Utils::GetClassName(HandleValue aObj, bool aUnwrap,
2176                                     JSContext* aCx, char** aRv) {
2177   if (!aObj.isObject()) {
2178     return NS_ERROR_INVALID_ARG;
2179   }
2180   RootedObject obj(aCx, &aObj.toObject());
2181   if (aUnwrap) {
2182     obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
2183   }
2184   *aRv = NS_xstrdup(JS::GetClass(obj)->name);
2185   return NS_OK;
2186 }
2187 
2188 NS_IMETHODIMP
GetDOMClassInfo(const nsAString & aClassName,nsIClassInfo ** aClassInfo)2189 nsXPCComponents_Utils::GetDOMClassInfo(const nsAString& aClassName,
2190                                        nsIClassInfo** aClassInfo) {
2191   *aClassInfo = nullptr;
2192   return NS_ERROR_NOT_AVAILABLE;
2193 }
2194 
2195 NS_IMETHODIMP
GetIncumbentGlobal(HandleValue aCallback,JSContext * aCx,MutableHandleValue aOut)2196 nsXPCComponents_Utils::GetIncumbentGlobal(HandleValue aCallback, JSContext* aCx,
2197                                           MutableHandleValue aOut) {
2198   nsCOMPtr<nsIGlobalObject> global = mozilla::dom::GetIncumbentGlobal();
2199   RootedValue globalVal(aCx);
2200 
2201   if (!global) {
2202     globalVal = NullValue();
2203   } else {
2204     // Note: We rely on the wrap call for outerization.
2205     globalVal = ObjectValue(*global->GetGlobalJSObject());
2206     if (!JS_WrapValue(aCx, &globalVal)) {
2207       return NS_ERROR_FAILURE;
2208     }
2209   }
2210 
2211   // Invoke the callback, if passed.
2212   if (aCallback.isObject()) {
2213     RootedValue ignored(aCx);
2214     if (!JS_CallFunctionValue(aCx, nullptr, aCallback,
2215                               JS::HandleValueArray(globalVal), &ignored)) {
2216       return NS_ERROR_FAILURE;
2217     }
2218   }
2219 
2220   aOut.set(globalVal);
2221   return NS_OK;
2222 }
2223 
2224 /*
2225  * Below is a bunch of awkward junk to allow JS test code to trigger the
2226  * creation of an XPCWrappedJS, such that it ends up in the map. We need to
2227  * hand the caller some sort of reference to hold onto (to prevent the
2228  * refcount from dropping to zero as soon as the function returns), but trying
2229  * to return a bonafide XPCWrappedJS to script causes all sorts of trouble. So
2230  * we create a benign holder class instead, which acts as an opaque reference
2231  * that script can use to keep the XPCWrappedJS alive and in the map.
2232  */
2233 
2234 class WrappedJSHolder : public nsISupports {
2235   NS_DECL_ISUPPORTS
2236   WrappedJSHolder() = default;
2237 
2238   RefPtr<nsXPCWrappedJS> mWrappedJS;
2239 
2240  private:
2241   virtual ~WrappedJSHolder() = default;
2242 };
2243 
2244 NS_IMPL_ADDREF(WrappedJSHolder)
2245 NS_IMPL_RELEASE(WrappedJSHolder)
2246 
2247 // nsINamed is always supported by nsXPCWrappedJS::DelegatedQueryInterface().
2248 // We expose this interface only for the identity in telemetry analysis.
2249 NS_INTERFACE_TABLE_HEAD(WrappedJSHolder)
2250   if (aIID.Equals(NS_GET_IID(nsINamed))) {
2251     return mWrappedJS->QueryInterface(aIID, aInstancePtr);
2252   }
NS_INTERFACE_TABLE0(WrappedJSHolder)2253   NS_INTERFACE_TABLE0(WrappedJSHolder)
2254 NS_INTERFACE_TABLE_TAIL
2255 
2256 NS_IMETHODIMP
2257 nsXPCComponents_Utils::GenerateXPCWrappedJS(HandleValue aObj,
2258                                             HandleValue aScope, JSContext* aCx,
2259                                             nsISupports** aOut) {
2260   if (!aObj.isObject()) {
2261     return NS_ERROR_INVALID_ARG;
2262   }
2263   RootedObject obj(aCx, &aObj.toObject());
2264   RootedObject scope(aCx, aScope.isObject()
2265                               ? js::UncheckedUnwrap(&aScope.toObject())
2266                               : CurrentGlobalOrNull(aCx));
2267   JSAutoRealm ar(aCx, scope);
2268   if (!JS_WrapObject(aCx, &obj)) {
2269     return NS_ERROR_FAILURE;
2270   }
2271 
2272   RefPtr<WrappedJSHolder> holder = new WrappedJSHolder();
2273   nsresult rv = nsXPCWrappedJS::GetNewOrUsed(
2274       aCx, obj, NS_GET_IID(nsISupports), getter_AddRefs(holder->mWrappedJS));
2275   holder.forget(aOut);
2276   return rv;
2277 }
2278 
2279 NS_IMETHODIMP
GetWatchdogTimestamp(const nsAString & aCategory,PRTime * aOut)2280 nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory,
2281                                             PRTime* aOut) {
2282   WatchdogTimestampCategory category;
2283   if (aCategory.EqualsLiteral("ContextStateChange")) {
2284     category = TimestampContextStateChange;
2285   } else if (aCategory.EqualsLiteral("WatchdogWakeup")) {
2286     category = TimestampWatchdogWakeup;
2287   } else if (aCategory.EqualsLiteral("WatchdogHibernateStart")) {
2288     category = TimestampWatchdogHibernateStart;
2289   } else if (aCategory.EqualsLiteral("WatchdogHibernateStop")) {
2290     category = TimestampWatchdogHibernateStop;
2291   } else {
2292     return NS_ERROR_INVALID_ARG;
2293   }
2294   *aOut = XPCJSContext::Get()->GetWatchdogTimestamp(category);
2295   return NS_OK;
2296 }
2297 
2298 NS_IMETHODIMP
GetJSEngineTelemetryValue(JSContext * cx,MutableHandleValue rval)2299 nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext* cx,
2300                                                  MutableHandleValue rval) {
2301   RootedObject obj(cx, JS_NewPlainObject(cx));
2302   if (!obj) {
2303     return NS_ERROR_OUT_OF_MEMORY;
2304   }
2305 
2306   // No JS engine telemetry in use at the moment.
2307 
2308   rval.setObject(*obj);
2309   return NS_OK;
2310 }
2311 
CloneInto(JSContext * aCx,HandleValue aValue,HandleValue aScope,HandleValue aOptions,MutableHandleValue aCloned)2312 bool xpc::CloneInto(JSContext* aCx, HandleValue aValue, HandleValue aScope,
2313                     HandleValue aOptions, MutableHandleValue aCloned) {
2314   if (!aScope.isObject()) {
2315     return false;
2316   }
2317 
2318   RootedObject scope(aCx, &aScope.toObject());
2319   // The scope could be a Window, so we need to CheckedUnwrapDynamic.
2320   scope = js::CheckedUnwrapDynamic(scope, aCx);
2321   if (!scope) {
2322     JS_ReportErrorASCII(aCx, "Permission denied to clone object into scope");
2323     return false;
2324   }
2325 
2326   if (!aOptions.isUndefined() && !aOptions.isObject()) {
2327     JS_ReportErrorASCII(aCx, "Invalid argument");
2328     return false;
2329   }
2330 
2331   RootedObject optionsObject(
2332       aCx, aOptions.isObject() ? &aOptions.toObject() : nullptr);
2333   StackScopedCloneOptions options(aCx, optionsObject);
2334   if (aOptions.isObject() && !options.Parse()) {
2335     return false;
2336   }
2337 
2338   js::AssertSameCompartment(aCx, aValue);
2339   RootedObject sourceScope(aCx, JS::CurrentGlobalOrNull(aCx));
2340 
2341   {
2342     JSAutoRealm ar(aCx, scope);
2343     aCloned.set(aValue);
2344     if (!StackScopedClone(aCx, options, sourceScope, aCloned)) {
2345       return false;
2346     }
2347   }
2348 
2349   return JS_WrapValue(aCx, aCloned);
2350 }
2351 
2352 NS_IMETHODIMP
CloneInto(HandleValue aValue,HandleValue aScope,HandleValue aOptions,JSContext * aCx,MutableHandleValue aCloned)2353 nsXPCComponents_Utils::CloneInto(HandleValue aValue, HandleValue aScope,
2354                                  HandleValue aOptions, JSContext* aCx,
2355                                  MutableHandleValue aCloned) {
2356   return xpc::CloneInto(aCx, aValue, aScope, aOptions, aCloned)
2357              ? NS_OK
2358              : NS_ERROR_FAILURE;
2359 }
2360 
2361 NS_IMETHODIMP
GetWebIDLCallerPrincipal(nsIPrincipal ** aResult)2362 nsXPCComponents_Utils::GetWebIDLCallerPrincipal(nsIPrincipal** aResult) {
2363   // This API may only be when the Entry Settings Object corresponds to a
2364   // JS-implemented WebIDL call. In all other cases, the value will be null,
2365   // and we throw.
2366   nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal();
2367   if (!callerPrin) {
2368     return NS_ERROR_NOT_AVAILABLE;
2369   }
2370   callerPrin.forget(aResult);
2371   return NS_OK;
2372 }
2373 
2374 NS_IMETHODIMP
GetObjectPrincipal(HandleValue val,JSContext * cx,nsIPrincipal ** result)2375 nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext* cx,
2376                                           nsIPrincipal** result) {
2377   if (!val.isObject()) {
2378     return NS_ERROR_INVALID_ARG;
2379   }
2380   RootedObject obj(cx, &val.toObject());
2381   // We need to be able to unwrap to WindowProxy or Location here, so
2382   // use CheckedUnwrapDynamic.
2383   obj = js::CheckedUnwrapDynamic(obj, cx);
2384   MOZ_ASSERT(obj);
2385 
2386   nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj);
2387   prin.forget(result);
2388   return NS_OK;
2389 }
2390 
2391 NS_IMETHODIMP
GetRealmLocation(HandleValue val,JSContext * cx,nsACString & result)2392 nsXPCComponents_Utils::GetRealmLocation(HandleValue val, JSContext* cx,
2393                                         nsACString& result) {
2394   if (!val.isObject()) {
2395     return NS_ERROR_INVALID_ARG;
2396   }
2397   RootedObject obj(cx, &val.toObject());
2398   // We need to be able to unwrap to WindowProxy or Location here, so
2399   // use CheckedUnwrapDynamic.
2400   obj = js::CheckedUnwrapDynamic(obj, cx);
2401   MOZ_ASSERT(obj);
2402 
2403   result = xpc::RealmPrivate::Get(obj)->GetLocation();
2404   return NS_OK;
2405 }
2406 
2407 NS_IMETHODIMP
ReadUTF8File(nsIFile * aFile,nsACString & aResult)2408 nsXPCComponents_Utils::ReadUTF8File(nsIFile* aFile, nsACString& aResult) {
2409   NS_ENSURE_TRUE(aFile, NS_ERROR_INVALID_ARG);
2410 
2411   MOZ_TRY_VAR(aResult, URLPreloader::ReadFile(aFile));
2412   return NS_OK;
2413 }
2414 
2415 NS_IMETHODIMP
ReadUTF8URI(nsIURI * aURI,nsACString & aResult)2416 nsXPCComponents_Utils::ReadUTF8URI(nsIURI* aURI, nsACString& aResult) {
2417   NS_ENSURE_TRUE(aURI, NS_ERROR_INVALID_ARG);
2418 
2419   MOZ_TRY_VAR(aResult, URLPreloader::ReadURI(aURI));
2420   return NS_OK;
2421 }
2422 
2423 NS_IMETHODIMP
Now(double * aRetval)2424 nsXPCComponents_Utils::Now(double* aRetval) {
2425   TimeStamp start = TimeStamp::ProcessCreation();
2426   *aRetval = (TimeStamp::Now() - start).ToMilliseconds();
2427   return NS_OK;
2428 }
2429 
2430 NS_IMETHODIMP
CreateSpellChecker(nsIEditorSpellCheck ** aSpellChecker)2431 nsXPCComponents_Utils::CreateSpellChecker(nsIEditorSpellCheck** aSpellChecker) {
2432   NS_ENSURE_ARG_POINTER(aSpellChecker);
2433   nsCOMPtr<nsIEditorSpellCheck> spellChecker = new mozilla::EditorSpellCheck();
2434   spellChecker.forget(aSpellChecker);
2435   return NS_OK;
2436 }
2437 
2438 NS_IMETHODIMP
CreateCommandLine(nsIFile * aWorkingDir,nsISupports ** aCommandLine)2439 nsXPCComponents_Utils::CreateCommandLine(nsIFile* aWorkingDir,
2440                                          nsISupports** aCommandLine) {
2441   NS_ENSURE_ARG_POINTER(aCommandLine);
2442   nsCOMPtr<nsISupports> commandLine = new nsCommandLine();
2443   if (aWorkingDir) {
2444     nsCOMPtr<nsICommandLineRunner> runner = do_QueryInterface(commandLine);
2445     char* argv[] = {nullptr};
2446     runner->Init(0, argv, aWorkingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
2447   }
2448 
2449   commandLine.forget(aCommandLine);
2450   return NS_OK;
2451 }
2452 
2453 NS_IMETHODIMP
CreateCommandParams(nsICommandParams ** aCommandParams)2454 nsXPCComponents_Utils::CreateCommandParams(nsICommandParams** aCommandParams) {
2455   NS_ENSURE_ARG_POINTER(aCommandParams);
2456   nsCOMPtr<nsICommandParams> commandParams = new nsCommandParams();
2457   commandParams.forget(aCommandParams);
2458   return NS_OK;
2459 }
2460 
2461 NS_IMETHODIMP
CreateLoadContext(nsILoadContext ** aLoadContext)2462 nsXPCComponents_Utils::CreateLoadContext(nsILoadContext** aLoadContext) {
2463   NS_ENSURE_ARG_POINTER(aLoadContext);
2464   nsCOMPtr<nsILoadContext> loadContext = ::CreateLoadContext();
2465   loadContext.forget(aLoadContext);
2466   return NS_OK;
2467 }
2468 
2469 NS_IMETHODIMP
CreatePrivateLoadContext(nsILoadContext ** aLoadContext)2470 nsXPCComponents_Utils::CreatePrivateLoadContext(nsILoadContext** aLoadContext) {
2471   NS_ENSURE_ARG_POINTER(aLoadContext);
2472   nsCOMPtr<nsILoadContext> loadContext = ::CreatePrivateLoadContext();
2473   loadContext.forget(aLoadContext);
2474   return NS_OK;
2475 }
2476 
2477 NS_IMETHODIMP
CreatePersistentProperties(nsIPersistentProperties ** aPersistentProperties)2478 nsXPCComponents_Utils::CreatePersistentProperties(
2479     nsIPersistentProperties** aPersistentProperties) {
2480   NS_ENSURE_ARG_POINTER(aPersistentProperties);
2481   nsCOMPtr<nsIPersistentProperties> props = new nsPersistentProperties();
2482   props.forget(aPersistentProperties);
2483   return NS_OK;
2484 }
2485 
2486 NS_IMETHODIMP
CreateDocumentEncoder(const char * aContentType,nsIDocumentEncoder ** aDocumentEncoder)2487 nsXPCComponents_Utils::CreateDocumentEncoder(
2488     const char* aContentType, nsIDocumentEncoder** aDocumentEncoder) {
2489   NS_ENSURE_ARG_POINTER(aDocumentEncoder);
2490   nsCOMPtr<nsIDocumentEncoder> encoder = do_createDocumentEncoder(aContentType);
2491   encoder.forget(aDocumentEncoder);
2492   return NS_OK;
2493 }
2494 
2495 NS_IMETHODIMP
CreateHTMLCopyEncoder(nsIDocumentEncoder ** aDocumentEncoder)2496 nsXPCComponents_Utils::CreateHTMLCopyEncoder(
2497     nsIDocumentEncoder** aDocumentEncoder) {
2498   NS_ENSURE_ARG_POINTER(aDocumentEncoder);
2499   nsCOMPtr<nsIDocumentEncoder> encoder = do_createHTMLCopyEncoder();
2500   encoder.forget(aDocumentEncoder);
2501   return NS_OK;
2502 }
2503 
2504 NS_IMETHODIMP
GetLoadedModules(nsTArray<nsCString> & aLoadedModules)2505 nsXPCComponents_Utils::GetLoadedModules(nsTArray<nsCString>& aLoadedModules) {
2506   mozJSComponentLoader::Get()->GetLoadedModules(aLoadedModules);
2507   return NS_OK;
2508 }
2509 
2510 NS_IMETHODIMP
GetLoadedComponents(nsTArray<nsCString> & aLoadedComponents)2511 nsXPCComponents_Utils::GetLoadedComponents(
2512     nsTArray<nsCString>& aLoadedComponents) {
2513   mozJSComponentLoader::Get()->GetLoadedComponents(aLoadedComponents);
2514   return NS_OK;
2515 }
2516 
2517 NS_IMETHODIMP
GetModuleImportStack(const nsACString & aLocation,nsACString & aRetval)2518 nsXPCComponents_Utils::GetModuleImportStack(const nsACString& aLocation,
2519                                             nsACString& aRetval) {
2520   return mozJSComponentLoader::Get()->GetModuleImportStack(aLocation, aRetval);
2521 }
2522 
2523 NS_IMETHODIMP
GetComponentLoadStack(const nsACString & aLocation,nsACString & aRetval)2524 nsXPCComponents_Utils::GetComponentLoadStack(const nsACString& aLocation,
2525                                              nsACString& aRetval) {
2526   return mozJSComponentLoader::Get()->GetComponentLoadStack(aLocation, aRetval);
2527 }
2528 
2529 /***************************************************************************/
2530 /***************************************************************************/
2531 /***************************************************************************/
2532 
nsXPCComponents(XPCWrappedNativeScope * aScope)2533 nsXPCComponents::nsXPCComponents(XPCWrappedNativeScope* aScope)
2534     : mScope(aScope) {
2535   MOZ_ASSERT(aScope, "aScope must not be null");
2536 }
2537 
2538 nsXPCComponents::~nsXPCComponents() = default;
2539 
ClearMembers()2540 void nsXPCComponents::ClearMembers() {
2541   mInterfaces = nullptr;
2542   mResults = nullptr;
2543   mClasses = nullptr;
2544   mID = nullptr;
2545   mException = nullptr;
2546   mConstructor = nullptr;
2547   mUtils = nullptr;
2548 }
2549 
2550 /*******************************************/
2551 #define XPC_IMPL_GET_OBJ_METHOD(_class, _n)                      \
2552   NS_IMETHODIMP _class::Get##_n(nsIXPCComponents_##_n** a##_n) { \
2553     NS_ENSURE_ARG_POINTER(a##_n);                                \
2554     if (!m##_n) m##_n = new nsXPCComponents_##_n();              \
2555     RefPtr<nsXPCComponents_##_n> ret = m##_n;                    \
2556     ret.forget(a##_n);                                           \
2557     return NS_OK;                                                \
2558   }
2559 
XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents,Interfaces)2560 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Interfaces)
2561 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Classes)
2562 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Results)
2563 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ID)
2564 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Exception)
2565 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Constructor)
2566 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Utils)
2567 
2568 #undef XPC_IMPL_GET_OBJ_METHOD
2569 /*******************************************/
2570 
2571 NS_IMETHODIMP
2572 nsXPCComponents::IsSuccessCode(nsresult result, bool* out) {
2573   *out = NS_SUCCEEDED(result);
2574   return NS_OK;
2575 }
2576 
2577 NS_IMETHODIMP
GetStack(nsIStackFrame ** aStack)2578 nsXPCComponents::GetStack(nsIStackFrame** aStack) {
2579   nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
2580   frame.forget(aStack);
2581   return NS_OK;
2582 }
2583 
2584 NS_IMETHODIMP
GetManager(nsIComponentManager ** aManager)2585 nsXPCComponents::GetManager(nsIComponentManager** aManager) {
2586   MOZ_ASSERT(aManager, "bad param");
2587   return NS_GetComponentManager(aManager);
2588 }
2589 
2590 NS_IMETHODIMP
GetReturnCode(JSContext * aCx,MutableHandleValue aOut)2591 nsXPCComponents::GetReturnCode(JSContext* aCx, MutableHandleValue aOut) {
2592   nsresult res = XPCJSContext::Get()->GetPendingResult();
2593   aOut.setNumber(static_cast<uint32_t>(res));
2594   return NS_OK;
2595 }
2596 
2597 NS_IMETHODIMP
SetReturnCode(JSContext * aCx,HandleValue aCode)2598 nsXPCComponents::SetReturnCode(JSContext* aCx, HandleValue aCode) {
2599   nsresult rv;
2600   if (!ToUint32(aCx, aCode, (uint32_t*)&rv)) {
2601     return NS_ERROR_FAILURE;
2602   }
2603   XPCJSContext::Get()->SetPendingResult(rv);
2604   return NS_OK;
2605 }
2606 
2607 /**********************************************/
2608 
2609 class ComponentsSH : public nsIXPCScriptable {
2610  public:
ComponentsSH(unsigned dummy)2611   explicit constexpr ComponentsSH(unsigned dummy) {}
2612 
2613   // We don't actually inherit any ref counting infrastructure, but we don't
2614   // need an nsAutoRefCnt member, so the _INHERITED macro is a hack to avoid
2615   // having one.
2616   NS_DECL_ISUPPORTS_INHERITED
2617   NS_DECL_NSIXPCSCRIPTABLE
Get(nsIXPCScriptable ** helper)2618   static nsresult Get(nsIXPCScriptable** helper) {
2619     *helper = &singleton;
2620     return NS_OK;
2621   }
2622 
2623  private:
2624   static ComponentsSH singleton;
2625 };
2626 
2627 ComponentsSH ComponentsSH::singleton(0);
2628 
2629 // Singleton refcounting.
NS_IMETHODIMP_(MozExternalRefCountType)2630 NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::AddRef(void) { return 1; }
NS_IMETHODIMP_(MozExternalRefCountType)2631 NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::Release(void) {
2632   return 1;
2633 }
2634 
NS_IMPL_QUERY_INTERFACE(ComponentsSH,nsIXPCScriptable)2635 NS_IMPL_QUERY_INTERFACE(ComponentsSH, nsIXPCScriptable)
2636 
2637 #define NSXPCCOMPONENTS_CID                          \
2638   {                                                  \
2639     0x3649f405, 0xf0ec, 0x4c28, {                    \
2640       0xae, 0xb0, 0xaf, 0x9a, 0x51, 0xe4, 0x4c, 0x81 \
2641     }                                                \
2642   }
2643 
2644 NS_IMPL_CLASSINFO(nsXPCComponents, &ComponentsSH::Get, 0, NSXPCCOMPONENTS_CID)
2645 NS_IMPL_ISUPPORTS_CI(nsXPCComponents, nsIXPCComponents)
2646 
2647 // The nsIXPCScriptable map declaration that will generate stubs for us
2648 #define XPC_MAP_CLASSNAME ComponentsSH
2649 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents"
2650 #define XPC_MAP_FLAGS XPC_SCRIPTABLE_WANT_PRECREATE
2651 #include "xpc_map_end.h" /* This will #undef the above */
2652 
2653 NS_IMETHODIMP
2654 ComponentsSH::PreCreate(nsISupports* nativeObj, JSContext* cx,
2655                         JSObject* globalObj, JSObject** parentObj) {
2656   nsXPCComponents* self = static_cast<nsXPCComponents*>(nativeObj);
2657   // this should never happen
2658   if (!self->GetScope()) {
2659     NS_WARNING(
2660         "mScope must not be null when nsXPCComponents::PreCreate is called");
2661     return NS_ERROR_FAILURE;
2662   }
2663   *parentObj = self->GetScope()->GetGlobalForWrappedNatives();
2664   return NS_OK;
2665 }
2666