|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */ |
|
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 /* High level class and public functions implementation. */ |
|
8 |
|
9 #include "mozilla/Assertions.h" |
|
10 #include "mozilla/Base64.h" |
|
11 #include "mozilla/Likely.h" |
|
12 |
|
13 #include "xpcprivate.h" |
|
14 #include "XPCWrapper.h" |
|
15 #include "jsfriendapi.h" |
|
16 #include "js/OldDebugAPI.h" |
|
17 #include "nsJSEnvironment.h" |
|
18 #include "nsThreadUtils.h" |
|
19 #include "nsDOMJSUtils.h" |
|
20 |
|
21 #include "WrapperFactory.h" |
|
22 #include "AccessCheck.h" |
|
23 |
|
24 #ifdef MOZ_JSDEBUGGER |
|
25 #include "jsdIDebuggerService.h" |
|
26 #endif |
|
27 |
|
28 #include "XPCQuickStubs.h" |
|
29 |
|
30 #include "mozilla/dom/BindingUtils.h" |
|
31 #include "mozilla/dom/Exceptions.h" |
|
32 #include "mozilla/dom/PromiseBinding.h" |
|
33 #include "mozilla/dom/TextDecoderBinding.h" |
|
34 #include "mozilla/dom/TextEncoderBinding.h" |
|
35 #include "mozilla/dom/DOMErrorBinding.h" |
|
36 |
|
37 #include "nsDOMMutationObserver.h" |
|
38 #include "nsICycleCollectorListener.h" |
|
39 #include "nsThread.h" |
|
40 #include "mozilla/XPTInterfaceInfoManager.h" |
|
41 #include "nsIObjectInputStream.h" |
|
42 #include "nsIObjectOutputStream.h" |
|
43 |
|
44 using namespace mozilla; |
|
45 using namespace mozilla::dom; |
|
46 using namespace xpc; |
|
47 using namespace JS; |
|
48 |
|
49 NS_IMPL_ISUPPORTS(nsXPConnect, |
|
50 nsIXPConnect, |
|
51 nsISupportsWeakReference, |
|
52 nsIThreadObserver, |
|
53 nsIJSRuntimeService) |
|
54 |
|
55 nsXPConnect* nsXPConnect::gSelf = nullptr; |
|
56 bool nsXPConnect::gOnceAliveNowDead = false; |
|
57 uint32_t nsXPConnect::gReportAllJSExceptions = 0; |
|
58 |
|
59 bool xpc::gDebugMode = false; |
|
60 bool xpc::gDesiredDebugMode = false; |
|
61 |
|
62 // Global cache of the default script security manager (QI'd to |
|
63 // nsIScriptSecurityManager) |
|
64 nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nullptr; |
|
65 |
|
66 const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1"; |
|
67 const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1"; |
|
68 const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1"; |
|
69 const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1"; |
|
70 const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1"; |
|
71 const char XPC_ID_CONTRACTID[] = "@mozilla.org/js/xpc/ID;1"; |
|
72 const char XPC_XPCONNECT_CONTRACTID[] = "@mozilla.org/js/xpc/XPConnect;1"; |
|
73 |
|
74 /***************************************************************************/ |
|
75 |
|
76 nsXPConnect::nsXPConnect() |
|
77 : mRuntime(nullptr), |
|
78 mShuttingDown(false), |
|
79 mEventDepth(0) |
|
80 { |
|
81 mRuntime = XPCJSRuntime::newXPCJSRuntime(this); |
|
82 |
|
83 char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS"); |
|
84 if (reportableEnv && *reportableEnv) |
|
85 gReportAllJSExceptions = 1; |
|
86 } |
|
87 |
|
88 nsXPConnect::~nsXPConnect() |
|
89 { |
|
90 mRuntime->DeleteSingletonScopes(); |
|
91 mRuntime->DestroyJSContextStack(); |
|
92 |
|
93 // In order to clean up everything properly, we need to GC twice: once now, |
|
94 // to clean anything that can go away on its own (like the Junk Scope, which |
|
95 // we unrooted above), and once after forcing a bunch of shutdown in |
|
96 // XPConnect, to clean the stuff we forcibly disconnected. The forced |
|
97 // shutdown code defaults to leaking in a number of situations, so we can't |
|
98 // get by with only the second GC. :-( |
|
99 JS_GC(mRuntime->Runtime()); |
|
100 |
|
101 mShuttingDown = true; |
|
102 XPCWrappedNativeScope::SystemIsBeingShutDown(); |
|
103 mRuntime->SystemIsBeingShutDown(); |
|
104 |
|
105 // The above causes us to clean up a bunch of XPConnect data structures, |
|
106 // after which point we need to GC to clean everything up. We need to do |
|
107 // this before deleting the XPCJSRuntime, because doing so destroys the |
|
108 // maps that our finalize callback depends on. |
|
109 JS_GC(mRuntime->Runtime()); |
|
110 |
|
111 mDefaultSecurityManager = nullptr; |
|
112 gScriptSecurityManager = nullptr; |
|
113 |
|
114 // shutdown the logging system |
|
115 XPC_LOG_FINISH(); |
|
116 |
|
117 delete mRuntime; |
|
118 |
|
119 gSelf = nullptr; |
|
120 gOnceAliveNowDead = true; |
|
121 } |
|
122 |
|
123 // static |
|
124 void |
|
125 nsXPConnect::InitStatics() |
|
126 { |
|
127 gSelf = new nsXPConnect(); |
|
128 gOnceAliveNowDead = false; |
|
129 if (!gSelf->mRuntime) { |
|
130 NS_RUNTIMEABORT("Couldn't create XPCJSRuntime."); |
|
131 } |
|
132 |
|
133 // Initial extra ref to keep the singleton alive |
|
134 // balanced by explicit call to ReleaseXPConnectSingleton() |
|
135 NS_ADDREF(gSelf); |
|
136 |
|
137 // Set XPConnect as the main thread observer. |
|
138 if (NS_FAILED(nsThread::SetMainThreadObserver(gSelf))) { |
|
139 MOZ_CRASH(); |
|
140 } |
|
141 } |
|
142 |
|
143 nsXPConnect* |
|
144 nsXPConnect::GetSingleton() |
|
145 { |
|
146 nsXPConnect* xpc = nsXPConnect::XPConnect(); |
|
147 NS_IF_ADDREF(xpc); |
|
148 return xpc; |
|
149 } |
|
150 |
|
151 // static |
|
152 void |
|
153 nsXPConnect::ReleaseXPConnectSingleton() |
|
154 { |
|
155 nsXPConnect* xpc = gSelf; |
|
156 if (xpc) { |
|
157 nsThread::SetMainThreadObserver(nullptr); |
|
158 |
|
159 nsrefcnt cnt; |
|
160 NS_RELEASE2(xpc, cnt); |
|
161 } |
|
162 } |
|
163 |
|
164 // static |
|
165 XPCJSRuntime* |
|
166 nsXPConnect::GetRuntimeInstance() |
|
167 { |
|
168 nsXPConnect* xpc = XPConnect(); |
|
169 return xpc->GetRuntime(); |
|
170 } |
|
171 |
|
172 // static |
|
173 bool |
|
174 nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info) |
|
175 { |
|
176 bool found = false; |
|
177 if (info) |
|
178 info->HasAncestor(&NS_GET_IID(nsISupports), &found); |
|
179 return found; |
|
180 } |
|
181 |
|
182 void |
|
183 xpc::SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep) |
|
184 { |
|
185 // It would be nice to assert !DescribeScriptedCaller here, to be sure |
|
186 // that there isn't any script running that could catch the exception. But |
|
187 // the JS engine invokes the error reporter directly if someone reports an |
|
188 // ErrorReport that it doesn't know how to turn into an exception. Arguably |
|
189 // it should just learn how to throw everything. But either way, if the |
|
190 // exception is ending here, it's not going to get propagated to a caller, |
|
191 // so it's up to us to make it known. |
|
192 |
|
193 nsresult rv; |
|
194 |
|
195 /* Use the console service to register the error. */ |
|
196 nsCOMPtr<nsIConsoleService> consoleService = |
|
197 do_GetService(NS_CONSOLESERVICE_CONTRACTID); |
|
198 |
|
199 /* |
|
200 * Make an nsIScriptError, populate it with information from this |
|
201 * error, then log it with the console service. |
|
202 */ |
|
203 nsCOMPtr<nsIScriptError> errorObject = |
|
204 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); |
|
205 |
|
206 if (consoleService && errorObject) { |
|
207 uint32_t column = rep->uctokenptr - rep->uclinebuf; |
|
208 |
|
209 const char16_t* ucmessage = |
|
210 static_cast<const char16_t*>(rep->ucmessage); |
|
211 const char16_t* uclinebuf = |
|
212 static_cast<const char16_t*>(rep->uclinebuf); |
|
213 |
|
214 rv = errorObject->Init( |
|
215 ucmessage ? nsDependentString(ucmessage) : EmptyString(), |
|
216 NS_ConvertASCIItoUTF16(rep->filename), |
|
217 uclinebuf ? nsDependentString(uclinebuf) : EmptyString(), |
|
218 rep->lineno, column, rep->flags, |
|
219 "system javascript"); |
|
220 if (NS_SUCCEEDED(rv)) |
|
221 consoleService->LogMessage(errorObject); |
|
222 } |
|
223 |
|
224 if (nsContentUtils::DOMWindowDumpEnabled()) { |
|
225 fprintf(stderr, "System JS : %s %s:%d - %s\n", |
|
226 JSREPORT_IS_WARNING(rep->flags) ? "WARNING" : "ERROR", |
|
227 rep->filename, rep->lineno, |
|
228 message ? message : "<no message>"); |
|
229 } |
|
230 |
|
231 } |
|
232 |
|
233 |
|
234 /***************************************************************************/ |
|
235 |
|
236 |
|
237 nsresult |
|
238 nsXPConnect::GetInfoForIID(const nsIID * aIID, nsIInterfaceInfo** info) |
|
239 { |
|
240 return XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(aIID, info); |
|
241 } |
|
242 |
|
243 nsresult |
|
244 nsXPConnect::GetInfoForName(const char * name, nsIInterfaceInfo** info) |
|
245 { |
|
246 nsresult rv = XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, info); |
|
247 return NS_FAILED(rv) ? NS_OK : NS_ERROR_NO_INTERFACE; |
|
248 } |
|
249 |
|
250 NS_IMETHODIMP |
|
251 nsXPConnect::GarbageCollect(uint32_t reason) |
|
252 { |
|
253 GetRuntime()->Collect(reason); |
|
254 return NS_OK; |
|
255 } |
|
256 |
|
257 bool |
|
258 xpc_GCThingIsGrayCCThing(void *thing) |
|
259 { |
|
260 return AddToCCKind(js::GCThingTraceKind(thing)) && |
|
261 xpc_IsGrayGCThing(thing); |
|
262 } |
|
263 |
|
264 void |
|
265 xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration) |
|
266 { |
|
267 nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant); |
|
268 if (variant) { |
|
269 variant->SetCCGeneration(aGeneration); |
|
270 variant->GetJSVal(); // Unmarks gray JSObject. |
|
271 XPCVariant* weak = variant.get(); |
|
272 variant = nullptr; |
|
273 if (weak->IsPurple()) { |
|
274 weak->RemovePurple(); |
|
275 } |
|
276 } |
|
277 } |
|
278 |
|
279 void |
|
280 xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS) |
|
281 { |
|
282 nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aWrappedJS); |
|
283 if (wjs) { |
|
284 // Unmarks gray JSObject. |
|
285 static_cast<nsXPCWrappedJS*>(wjs.get())->GetJSObject(); |
|
286 } |
|
287 } |
|
288 |
|
289 /***************************************************************************/ |
|
290 /***************************************************************************/ |
|
291 // nsIXPConnect interface methods... |
|
292 |
|
293 template<typename T> |
|
294 static inline T UnexpectedFailure(T rv) |
|
295 { |
|
296 NS_ERROR("This is not supposed to fail!"); |
|
297 return rv; |
|
298 } |
|
299 |
|
300 /* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */ |
|
301 NS_IMETHODIMP |
|
302 nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj) |
|
303 { |
|
304 MOZ_ASSERT(aJSContext, "bad param"); |
|
305 MOZ_ASSERT(aGlobalJSObj, "bad param"); |
|
306 RootedObject globalJSObj(aJSContext, aGlobalJSObj); |
|
307 |
|
308 JSAutoCompartment ac(aJSContext, globalJSObj); |
|
309 |
|
310 XPCWrappedNativeScope* scope = |
|
311 XPCWrappedNativeScope::GetNewOrUsed(aJSContext, globalJSObj); |
|
312 |
|
313 if (!scope) |
|
314 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
315 |
|
316 scope->RemoveWrappedNativeProtos(); |
|
317 |
|
318 if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj)) |
|
319 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
320 |
|
321 return NS_OK; |
|
322 } |
|
323 |
|
324 #ifdef DEBUG |
|
325 static void |
|
326 VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind) |
|
327 { |
|
328 // We don't do anything here, we only want to verify that TraceXPCGlobal |
|
329 // was called. |
|
330 } |
|
331 |
|
332 struct VerifyTraceXPCGlobalCalledTracer : public JSTracer |
|
333 { |
|
334 bool ok; |
|
335 |
|
336 VerifyTraceXPCGlobalCalledTracer(JSRuntime *rt) |
|
337 : JSTracer(rt, VerifyTraceXPCGlobalCalled), ok(false) |
|
338 {} |
|
339 }; |
|
340 #endif |
|
341 |
|
342 void |
|
343 xpc::TraceXPCGlobal(JSTracer *trc, JSObject *obj) |
|
344 { |
|
345 #ifdef DEBUG |
|
346 if (trc->callback == VerifyTraceXPCGlobalCalled) { |
|
347 // We don't do anything here, we only want to verify that TraceXPCGlobal |
|
348 // was called. |
|
349 reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true; |
|
350 return; |
|
351 } |
|
352 #endif |
|
353 |
|
354 if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL) |
|
355 mozilla::dom::TraceProtoAndIfaceCache(trc, obj); |
|
356 |
|
357 // We might be called from a GC during the creation of a global, before we've |
|
358 // been able to set up the compartment private or the XPCWrappedNativeScope, |
|
359 // so we need to null-check those. |
|
360 xpc::CompartmentPrivate* compartmentPrivate = GetCompartmentPrivate(obj); |
|
361 if (compartmentPrivate && compartmentPrivate->scope) |
|
362 compartmentPrivate->scope->TraceInside(trc); |
|
363 } |
|
364 |
|
365 namespace xpc { |
|
366 |
|
367 JSObject* |
|
368 CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal, |
|
369 JS::CompartmentOptions& aOptions) |
|
370 { |
|
371 MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?"); |
|
372 MOZ_ASSERT(principal); |
|
373 |
|
374 RootedObject global(cx, |
|
375 JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal), |
|
376 JS::DontFireOnNewGlobalHook, aOptions)); |
|
377 if (!global) |
|
378 return nullptr; |
|
379 JSAutoCompartment ac(cx, global); |
|
380 |
|
381 // The constructor automatically attaches the scope to the compartment private |
|
382 // of |global|. |
|
383 (void) new XPCWrappedNativeScope(cx, global); |
|
384 |
|
385 #ifdef DEBUG |
|
386 // Verify that the right trace hook is called. Note that this doesn't |
|
387 // work right for wrapped globals, since the tracing situation there is |
|
388 // more complicated. Manual inspection shows that they do the right thing. |
|
389 if (!((const js::Class*)clasp)->ext.isWrappedNative) |
|
390 { |
|
391 VerifyTraceXPCGlobalCalledTracer trc(JS_GetRuntime(cx)); |
|
392 JS_TraceChildren(&trc, global, JSTRACE_OBJECT); |
|
393 MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments."); |
|
394 } |
|
395 #endif |
|
396 |
|
397 if (clasp->flags & JSCLASS_DOM_GLOBAL) { |
|
398 const char* className = clasp->name; |
|
399 AllocateProtoAndIfaceCache(global, |
|
400 (strcmp(className, "Window") == 0 || |
|
401 strcmp(className, "ChromeWindow") == 0) |
|
402 ? ProtoAndIfaceCache::WindowLike |
|
403 : ProtoAndIfaceCache::NonWindowLike); |
|
404 } |
|
405 |
|
406 return global; |
|
407 } |
|
408 |
|
409 bool |
|
410 InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags) |
|
411 { |
|
412 // Immediately enter the global's compartment, so that everything else we |
|
413 // create ends up there. |
|
414 JSAutoCompartment ac(aJSContext, aGlobal); |
|
415 if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) { |
|
416 // XPCCallContext gives us an active request needed to save/restore. |
|
417 if (!GetCompartmentPrivate(aGlobal)->scope->AttachComponentsObject(aJSContext) || |
|
418 !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) { |
|
419 return UnexpectedFailure(false); |
|
420 } |
|
421 } |
|
422 |
|
423 if (ShouldDiscardSystemSource()) { |
|
424 nsIPrincipal *prin = GetObjectPrincipal(aGlobal); |
|
425 bool isSystem = nsContentUtils::IsSystemPrincipal(prin); |
|
426 if (!isSystem) { |
|
427 short status = prin->GetAppStatus(); |
|
428 isSystem = status == nsIPrincipal::APP_STATUS_PRIVILEGED || |
|
429 status == nsIPrincipal::APP_STATUS_CERTIFIED; |
|
430 } |
|
431 JS::CompartmentOptionsRef(aGlobal).setDiscardSource(isSystem); |
|
432 } |
|
433 |
|
434 // Stuff coming through this path always ends up as a DOM global. |
|
435 MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL); |
|
436 |
|
437 // Init WebIDL binding constructors wanted on all XPConnect globals. |
|
438 // |
|
439 // XXX Please do not add any additional classes here without the approval of |
|
440 // the XPConnect module owner. |
|
441 if (!PromiseBinding::GetConstructorObject(aJSContext, aGlobal) || |
|
442 !TextDecoderBinding::GetConstructorObject(aJSContext, aGlobal) || |
|
443 !TextEncoderBinding::GetConstructorObject(aJSContext, aGlobal) || |
|
444 !DOMErrorBinding::GetConstructorObject(aJSContext, aGlobal)) { |
|
445 return UnexpectedFailure(false); |
|
446 } |
|
447 |
|
448 if (!(aFlags & nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK)) |
|
449 JS_FireOnNewGlobalObject(aJSContext, aGlobal); |
|
450 |
|
451 return true; |
|
452 } |
|
453 |
|
454 } // namespace xpc |
|
455 |
|
456 NS_IMETHODIMP |
|
457 nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, |
|
458 nsISupports *aCOMObj, |
|
459 nsIPrincipal * aPrincipal, |
|
460 uint32_t aFlags, |
|
461 JS::CompartmentOptions& aOptions, |
|
462 nsIXPConnectJSObjectHolder **_retval) |
|
463 { |
|
464 MOZ_ASSERT(aJSContext, "bad param"); |
|
465 MOZ_ASSERT(aCOMObj, "bad param"); |
|
466 MOZ_ASSERT(_retval, "bad param"); |
|
467 |
|
468 // We pass null for the 'extra' pointer during global object creation, so |
|
469 // we need to have a principal. |
|
470 MOZ_ASSERT(aPrincipal); |
|
471 |
|
472 // Call into XPCWrappedNative to make a new global object, scope, and global |
|
473 // prototype. |
|
474 xpcObjectHelper helper(aCOMObj); |
|
475 MOZ_ASSERT(helper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT); |
|
476 nsRefPtr<XPCWrappedNative> wrappedGlobal; |
|
477 nsresult rv = |
|
478 XPCWrappedNative::WrapNewGlobal(helper, aPrincipal, |
|
479 aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES, |
|
480 aOptions, getter_AddRefs(wrappedGlobal)); |
|
481 NS_ENSURE_SUCCESS(rv, rv); |
|
482 |
|
483 // Grab a copy of the global and enter its compartment. |
|
484 RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject()); |
|
485 MOZ_ASSERT(!js::GetObjectParent(global)); |
|
486 |
|
487 if (!InitGlobalObject(aJSContext, global, aFlags)) |
|
488 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
489 |
|
490 wrappedGlobal.forget(_retval); |
|
491 return NS_OK; |
|
492 } |
|
493 |
|
494 static nsresult |
|
495 NativeInterface2JSObject(HandleObject aScope, |
|
496 nsISupports *aCOMObj, |
|
497 nsWrapperCache *aCache, |
|
498 const nsIID * aIID, |
|
499 bool aAllowWrapping, |
|
500 MutableHandleValue aVal, |
|
501 nsIXPConnectJSObjectHolder **aHolder) |
|
502 { |
|
503 AutoJSContext cx; |
|
504 JSAutoCompartment ac(cx, aScope); |
|
505 |
|
506 nsresult rv; |
|
507 xpcObjectHelper helper(aCOMObj, aCache); |
|
508 if (!XPCConvert::NativeInterface2JSObject(aVal, aHolder, helper, aIID, |
|
509 nullptr, aAllowWrapping, &rv)) |
|
510 return rv; |
|
511 |
|
512 MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()), |
|
513 "Shouldn't be returning a xray wrapper here"); |
|
514 |
|
515 return NS_OK; |
|
516 } |
|
517 |
|
518 /* nsIXPConnectJSObjectHolder wrapNative (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */ |
|
519 NS_IMETHODIMP |
|
520 nsXPConnect::WrapNative(JSContext * aJSContext, |
|
521 JSObject * aScopeArg, |
|
522 nsISupports *aCOMObj, |
|
523 const nsIID & aIID, |
|
524 nsIXPConnectJSObjectHolder **aHolder) |
|
525 { |
|
526 MOZ_ASSERT(aHolder, "bad param"); |
|
527 MOZ_ASSERT(aJSContext, "bad param"); |
|
528 MOZ_ASSERT(aScopeArg, "bad param"); |
|
529 MOZ_ASSERT(aCOMObj, "bad param"); |
|
530 |
|
531 RootedObject aScope(aJSContext, aScopeArg); |
|
532 RootedValue v(aJSContext); |
|
533 return NativeInterface2JSObject(aScope, aCOMObj, nullptr, &aIID, |
|
534 true, &v, aHolder); |
|
535 } |
|
536 |
|
537 /* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */ |
|
538 NS_IMETHODIMP |
|
539 nsXPConnect::WrapNativeToJSVal(JSContext *aJSContext, |
|
540 JSObject *aScopeArg, |
|
541 nsISupports *aCOMObj, |
|
542 nsWrapperCache *aCache, |
|
543 const nsIID *aIID, |
|
544 bool aAllowWrapping, |
|
545 MutableHandleValue aVal) |
|
546 { |
|
547 MOZ_ASSERT(aJSContext, "bad param"); |
|
548 MOZ_ASSERT(aScopeArg, "bad param"); |
|
549 MOZ_ASSERT(aCOMObj, "bad param"); |
|
550 |
|
551 RootedObject aScope(aJSContext, aScopeArg); |
|
552 return NativeInterface2JSObject(aScope, aCOMObj, aCache, aIID, |
|
553 aAllowWrapping, aVal, nullptr); |
|
554 } |
|
555 |
|
556 /* void wrapJS (in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */ |
|
557 NS_IMETHODIMP |
|
558 nsXPConnect::WrapJS(JSContext * aJSContext, |
|
559 JSObject * aJSObjArg, |
|
560 const nsIID & aIID, |
|
561 void * *result) |
|
562 { |
|
563 MOZ_ASSERT(aJSContext, "bad param"); |
|
564 MOZ_ASSERT(aJSObjArg, "bad param"); |
|
565 MOZ_ASSERT(result, "bad param"); |
|
566 |
|
567 *result = nullptr; |
|
568 |
|
569 RootedObject aJSObj(aJSContext, aJSObjArg); |
|
570 JSAutoCompartment ac(aJSContext, aJSObj); |
|
571 |
|
572 nsresult rv = NS_ERROR_UNEXPECTED; |
|
573 if (!XPCConvert::JSObject2NativeInterface(result, aJSObj, |
|
574 &aIID, nullptr, &rv)) |
|
575 return rv; |
|
576 return NS_OK; |
|
577 } |
|
578 |
|
579 NS_IMETHODIMP |
|
580 nsXPConnect::JSValToVariant(JSContext *cx, |
|
581 HandleValue aJSVal, |
|
582 nsIVariant **aResult) |
|
583 { |
|
584 NS_PRECONDITION(aResult, "bad param"); |
|
585 |
|
586 nsRefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal); |
|
587 variant.forget(aResult); |
|
588 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); |
|
589 |
|
590 return NS_OK; |
|
591 } |
|
592 |
|
593 /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */ |
|
594 NS_IMETHODIMP |
|
595 nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter, |
|
596 JSContext *aJSContext, |
|
597 JSObject *aJSObjArg, |
|
598 const nsIID &aIID, |
|
599 void **result) |
|
600 { |
|
601 MOZ_ASSERT(aOuter, "bad param"); |
|
602 MOZ_ASSERT(aJSContext, "bad param"); |
|
603 MOZ_ASSERT(aJSObjArg, "bad param"); |
|
604 MOZ_ASSERT(result, "bad param"); |
|
605 |
|
606 *result = nullptr; |
|
607 |
|
608 RootedObject aJSObj(aJSContext, aJSObjArg); |
|
609 nsresult rv; |
|
610 if (!XPCConvert::JSObject2NativeInterface(result, aJSObj, |
|
611 &aIID, aOuter, &rv)) |
|
612 return rv; |
|
613 return NS_OK; |
|
614 } |
|
615 |
|
616 /* nsIXPConnectWrappedNative getWrappedNativeOfJSObject (in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */ |
|
617 NS_IMETHODIMP |
|
618 nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext, |
|
619 JSObject * aJSObjArg, |
|
620 nsIXPConnectWrappedNative **_retval) |
|
621 { |
|
622 MOZ_ASSERT(aJSContext, "bad param"); |
|
623 MOZ_ASSERT(aJSObjArg, "bad param"); |
|
624 MOZ_ASSERT(_retval, "bad param"); |
|
625 |
|
626 RootedObject aJSObj(aJSContext, aJSObjArg); |
|
627 aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false); |
|
628 if (!aJSObj || !IS_WN_REFLECTOR(aJSObj)) { |
|
629 *_retval = nullptr; |
|
630 return NS_ERROR_FAILURE; |
|
631 } |
|
632 |
|
633 nsRefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj); |
|
634 temp.forget(_retval); |
|
635 return NS_OK; |
|
636 } |
|
637 |
|
638 /* nsISupports getNativeOfWrapper(in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */ |
|
639 NS_IMETHODIMP_(nsISupports*) |
|
640 nsXPConnect::GetNativeOfWrapper(JSContext *aJSContext, |
|
641 JSObject *aJSObj) |
|
642 { |
|
643 MOZ_ASSERT(aJSContext, "bad param"); |
|
644 MOZ_ASSERT(aJSObj, "bad param"); |
|
645 |
|
646 aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false); |
|
647 if (!aJSObj) { |
|
648 JS_ReportError(aJSContext, "Permission denied to get native of security wrapper"); |
|
649 return nullptr; |
|
650 } |
|
651 if (IS_WN_REFLECTOR(aJSObj)) { |
|
652 if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj)) |
|
653 return wn->Native(); |
|
654 return nullptr; |
|
655 } |
|
656 |
|
657 nsCOMPtr<nsISupports> canonical = |
|
658 do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(aJSObj)); |
|
659 return canonical; |
|
660 } |
|
661 |
|
662 /* nsIXPConnectWrappedNative getWrappedNativeOfNativeObject (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDRef aIID); */ |
|
663 NS_IMETHODIMP |
|
664 nsXPConnect::GetWrappedNativeOfNativeObject(JSContext * aJSContext, |
|
665 JSObject * aScopeArg, |
|
666 nsISupports *aCOMObj, |
|
667 const nsIID & aIID, |
|
668 nsIXPConnectWrappedNative **_retval) |
|
669 { |
|
670 MOZ_ASSERT(aJSContext, "bad param"); |
|
671 MOZ_ASSERT(aScopeArg, "bad param"); |
|
672 MOZ_ASSERT(aCOMObj, "bad param"); |
|
673 MOZ_ASSERT(_retval, "bad param"); |
|
674 |
|
675 *_retval = nullptr; |
|
676 |
|
677 RootedObject aScope(aJSContext, aScopeArg); |
|
678 |
|
679 XPCWrappedNativeScope* scope = GetObjectScope(aScope); |
|
680 if (!scope) |
|
681 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
682 |
|
683 AutoMarkingNativeInterfacePtr iface(aJSContext); |
|
684 iface = XPCNativeInterface::GetNewOrUsed(&aIID); |
|
685 if (!iface) |
|
686 return NS_ERROR_FAILURE; |
|
687 |
|
688 XPCWrappedNative* wrapper; |
|
689 |
|
690 nsresult rv = XPCWrappedNative::GetUsedOnly(aCOMObj, scope, iface, &wrapper); |
|
691 if (NS_FAILED(rv)) |
|
692 return NS_ERROR_FAILURE; |
|
693 *_retval = static_cast<nsIXPConnectWrappedNative*>(wrapper); |
|
694 return NS_OK; |
|
695 } |
|
696 |
|
697 /* void reparentWrappedNativeIfFound (in JSContextPtr aJSContext, |
|
698 * in JSObjectPtr aScope, |
|
699 * in JSObjectPtr aNewParent, |
|
700 * in nsISupports aCOMObj); */ |
|
701 NS_IMETHODIMP |
|
702 nsXPConnect::ReparentWrappedNativeIfFound(JSContext * aJSContext, |
|
703 JSObject * aScopeArg, |
|
704 JSObject * aNewParentArg, |
|
705 nsISupports *aCOMObj) |
|
706 { |
|
707 RootedObject aScope(aJSContext, aScopeArg); |
|
708 RootedObject aNewParent(aJSContext, aNewParentArg); |
|
709 |
|
710 XPCWrappedNativeScope* scope = GetObjectScope(aScope); |
|
711 XPCWrappedNativeScope* scope2 = GetObjectScope(aNewParent); |
|
712 if (!scope || !scope2) |
|
713 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
714 |
|
715 RootedObject newParent(aJSContext, aNewParent); |
|
716 return XPCWrappedNative:: |
|
717 ReparentWrapperIfFound(scope, scope2, newParent, aCOMObj); |
|
718 } |
|
719 |
|
720 static PLDHashOperator |
|
721 MoveableWrapperFinder(PLDHashTable *table, PLDHashEntryHdr *hdr, |
|
722 uint32_t number, void *arg) |
|
723 { |
|
724 nsTArray<nsRefPtr<XPCWrappedNative> > *array = |
|
725 static_cast<nsTArray<nsRefPtr<XPCWrappedNative> > *>(arg); |
|
726 XPCWrappedNative *wn = ((Native2WrappedNativeMap::Entry*)hdr)->value; |
|
727 |
|
728 // If a wrapper is expired, then there are no references to it from JS, so |
|
729 // we don't have to move it. |
|
730 if (!wn->IsWrapperExpired()) |
|
731 array->AppendElement(wn); |
|
732 return PL_DHASH_NEXT; |
|
733 } |
|
734 |
|
735 /* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr aScope); */ |
|
736 NS_IMETHODIMP |
|
737 nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScopeArg) |
|
738 { |
|
739 RootedObject aScope(aJSContext, aScopeArg); |
|
740 |
|
741 XPCWrappedNativeScope *scope = GetObjectScope(aScope); |
|
742 if (!scope) |
|
743 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
744 |
|
745 // First, look through the old scope and find all of the wrappers that we |
|
746 // might need to rescue. |
|
747 nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove; |
|
748 |
|
749 Native2WrappedNativeMap *map = scope->GetWrappedNativeMap(); |
|
750 wrappersToMove.SetCapacity(map->Count()); |
|
751 map->Enumerate(MoveableWrapperFinder, &wrappersToMove); |
|
752 |
|
753 // Now that we have the wrappers, reparent them to the new scope. |
|
754 for (uint32_t i = 0, stop = wrappersToMove.Length(); i < stop; ++i) { |
|
755 nsresult rv = wrappersToMove[i]->RescueOrphans(); |
|
756 NS_ENSURE_SUCCESS(rv, rv); |
|
757 } |
|
758 |
|
759 return NS_OK; |
|
760 } |
|
761 |
|
762 /* void setDefaultSecurityManager (in nsIXPCSecurityManager aManager); */ |
|
763 NS_IMETHODIMP |
|
764 nsXPConnect::SetDefaultSecurityManager(nsIXPCSecurityManager *aManager) |
|
765 { |
|
766 mDefaultSecurityManager = aManager; |
|
767 |
|
768 nsCOMPtr<nsIScriptSecurityManager> ssm = |
|
769 do_QueryInterface(mDefaultSecurityManager); |
|
770 |
|
771 // Remember the result of the above QI for fast access to the |
|
772 // script securityt manager. |
|
773 gScriptSecurityManager = ssm; |
|
774 |
|
775 return NS_OK; |
|
776 } |
|
777 |
|
778 /* nsIStackFrame createStackFrameLocation (in uint32_t aLanguage, in string aFilename, in string aFunctionName, in int32_t aLineNumber, in nsIStackFrame aCaller); */ |
|
779 NS_IMETHODIMP |
|
780 nsXPConnect::CreateStackFrameLocation(uint32_t aLanguage, |
|
781 const char *aFilename, |
|
782 const char *aFunctionName, |
|
783 int32_t aLineNumber, |
|
784 nsIStackFrame *aCaller, |
|
785 nsIStackFrame **_retval) |
|
786 { |
|
787 MOZ_ASSERT(_retval, "bad param"); |
|
788 |
|
789 nsCOMPtr<nsIStackFrame> stackFrame = |
|
790 exceptions::CreateStackFrameLocation(aLanguage, |
|
791 aFilename, |
|
792 aFunctionName, |
|
793 aLineNumber, |
|
794 aCaller); |
|
795 stackFrame.forget(_retval); |
|
796 return NS_OK; |
|
797 } |
|
798 |
|
799 /* readonly attribute nsIStackFrame CurrentJSStack; */ |
|
800 NS_IMETHODIMP |
|
801 nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack) |
|
802 { |
|
803 MOZ_ASSERT(aCurrentJSStack, "bad param"); |
|
804 |
|
805 nsCOMPtr<nsIStackFrame> currentStack = dom::GetCurrentJSStack(); |
|
806 currentStack.forget(aCurrentJSStack); |
|
807 |
|
808 return NS_OK; |
|
809 } |
|
810 |
|
811 /* readonly attribute nsIXPCNativeCallContext CurrentNativeCallContext; */ |
|
812 NS_IMETHODIMP |
|
813 nsXPConnect::GetCurrentNativeCallContext(nsAXPCNativeCallContext * *aCurrentNativeCallContext) |
|
814 { |
|
815 MOZ_ASSERT(aCurrentNativeCallContext, "bad param"); |
|
816 |
|
817 *aCurrentNativeCallContext = XPCJSRuntime::Get()->GetCallContext(); |
|
818 return NS_OK; |
|
819 } |
|
820 |
|
821 /* void setFunctionThisTranslator (in nsIIDRef aIID, in nsIXPCFunctionThisTranslator aTranslator); */ |
|
822 NS_IMETHODIMP |
|
823 nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID, |
|
824 nsIXPCFunctionThisTranslator *aTranslator) |
|
825 { |
|
826 XPCJSRuntime* rt = GetRuntime(); |
|
827 IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap(); |
|
828 map->Add(aIID, aTranslator); |
|
829 return NS_OK; |
|
830 } |
|
831 |
|
832 NS_IMETHODIMP |
|
833 nsXPConnect::CreateSandbox(JSContext *cx, nsIPrincipal *principal, |
|
834 nsIXPConnectJSObjectHolder **_retval) |
|
835 { |
|
836 *_retval = nullptr; |
|
837 |
|
838 RootedValue rval(cx); |
|
839 SandboxOptions options; |
|
840 nsresult rv = CreateSandboxObject(cx, &rval, principal, options); |
|
841 MOZ_ASSERT(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval), |
|
842 "Bad return value from xpc_CreateSandboxObject()!"); |
|
843 |
|
844 if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) { |
|
845 *_retval = XPCJSObjectHolder::newHolder(JSVAL_TO_OBJECT(rval)); |
|
846 NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY); |
|
847 |
|
848 NS_ADDREF(*_retval); |
|
849 } |
|
850 |
|
851 return rv; |
|
852 } |
|
853 |
|
854 NS_IMETHODIMP |
|
855 nsXPConnect::EvalInSandboxObject(const nsAString& source, const char *filename, |
|
856 JSContext *cx, JSObject *sandboxArg, |
|
857 bool returnStringOnly, MutableHandleValue rval) |
|
858 { |
|
859 if (!sandboxArg) |
|
860 return NS_ERROR_INVALID_ARG; |
|
861 |
|
862 RootedObject sandbox(cx, sandboxArg); |
|
863 nsCString filenameStr; |
|
864 if (filename) { |
|
865 filenameStr.Assign(filename); |
|
866 } else { |
|
867 filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox"); |
|
868 } |
|
869 return EvalInSandbox(cx, sandbox, source, filenameStr, 1, |
|
870 JSVERSION_DEFAULT, returnStringOnly, rval); |
|
871 } |
|
872 |
|
873 /* nsIXPConnectJSObjectHolder getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsIClassInfo aClassInfo); */ |
|
874 NS_IMETHODIMP |
|
875 nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext, |
|
876 JSObject * aScopeArg, |
|
877 nsIClassInfo *aClassInfo, |
|
878 nsIXPConnectJSObjectHolder **_retval) |
|
879 { |
|
880 RootedObject aScope(aJSContext, aScopeArg); |
|
881 JSAutoCompartment ac(aJSContext, aScope); |
|
882 |
|
883 XPCWrappedNativeScope* scope = GetObjectScope(aScope); |
|
884 if (!scope) |
|
885 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
886 |
|
887 XPCNativeScriptableCreateInfo sciProto; |
|
888 XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto); |
|
889 |
|
890 AutoMarkingWrappedNativeProtoPtr proto(aJSContext); |
|
891 proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, &sciProto); |
|
892 if (!proto) |
|
893 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
894 |
|
895 nsIXPConnectJSObjectHolder* holder; |
|
896 *_retval = holder = XPCJSObjectHolder::newHolder(proto->GetJSProtoObject()); |
|
897 if (!holder) |
|
898 return UnexpectedFailure(NS_ERROR_FAILURE); |
|
899 |
|
900 NS_ADDREF(holder); |
|
901 return NS_OK; |
|
902 } |
|
903 |
|
904 /* void debugDump (in short depth); */ |
|
905 NS_IMETHODIMP |
|
906 nsXPConnect::DebugDump(int16_t depth) |
|
907 { |
|
908 #ifdef DEBUG |
|
909 depth-- ; |
|
910 XPC_LOG_ALWAYS(("nsXPConnect @ %x with mRefCnt = %d", this, mRefCnt.get())); |
|
911 XPC_LOG_INDENT(); |
|
912 XPC_LOG_ALWAYS(("gSelf @ %x", gSelf)); |
|
913 XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead)); |
|
914 XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager.get())); |
|
915 if (mRuntime) { |
|
916 if (depth) |
|
917 mRuntime->DebugDump(depth); |
|
918 else |
|
919 XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime)); |
|
920 } else |
|
921 XPC_LOG_ALWAYS(("mRuntime is null")); |
|
922 XPCWrappedNativeScope::DebugDumpAllScopes(depth); |
|
923 XPC_LOG_OUTDENT(); |
|
924 #endif |
|
925 return NS_OK; |
|
926 } |
|
927 |
|
928 /* void debugDumpObject (in nsISupports aCOMObj, in short depth); */ |
|
929 NS_IMETHODIMP |
|
930 nsXPConnect::DebugDumpObject(nsISupports *p, int16_t depth) |
|
931 { |
|
932 #ifdef DEBUG |
|
933 if (!depth) |
|
934 return NS_OK; |
|
935 if (!p) { |
|
936 XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address")); |
|
937 return NS_OK; |
|
938 } |
|
939 |
|
940 nsIXPConnect* xpc; |
|
941 nsIXPCWrappedJSClass* wjsc; |
|
942 nsIXPConnectWrappedNative* wn; |
|
943 nsIXPConnectWrappedJS* wjs; |
|
944 |
|
945 if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnect), |
|
946 (void**)&xpc))) { |
|
947 XPC_LOG_ALWAYS(("Dumping a nsIXPConnect...")); |
|
948 xpc->DebugDump(depth); |
|
949 NS_RELEASE(xpc); |
|
950 } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPCWrappedJSClass), |
|
951 (void**)&wjsc))) { |
|
952 XPC_LOG_ALWAYS(("Dumping a nsIXPCWrappedJSClass...")); |
|
953 wjsc->DebugDump(depth); |
|
954 NS_RELEASE(wjsc); |
|
955 } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedNative), |
|
956 (void**)&wn))) { |
|
957 XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative...")); |
|
958 wn->DebugDump(depth); |
|
959 NS_RELEASE(wn); |
|
960 } else if (NS_SUCCEEDED(p->QueryInterface(NS_GET_IID(nsIXPConnectWrappedJS), |
|
961 (void**)&wjs))) { |
|
962 XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS...")); |
|
963 wjs->DebugDump(depth); |
|
964 NS_RELEASE(wjs); |
|
965 } else |
|
966 XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %x", p)); |
|
967 #endif |
|
968 return NS_OK; |
|
969 } |
|
970 |
|
971 /* void debugDumpJSStack (in bool showArgs, in bool showLocals, in bool showThisProps); */ |
|
972 NS_IMETHODIMP |
|
973 nsXPConnect::DebugDumpJSStack(bool showArgs, |
|
974 bool showLocals, |
|
975 bool showThisProps) |
|
976 { |
|
977 JSContext* cx = GetCurrentJSContext(); |
|
978 if (!cx) |
|
979 printf("there is no JSContext on the nsIThreadJSContextStack!\n"); |
|
980 else |
|
981 xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps); |
|
982 |
|
983 return NS_OK; |
|
984 } |
|
985 |
|
986 char* |
|
987 nsXPConnect::DebugPrintJSStack(bool showArgs, |
|
988 bool showLocals, |
|
989 bool showThisProps) |
|
990 { |
|
991 JSContext* cx = GetCurrentJSContext(); |
|
992 if (!cx) |
|
993 printf("there is no JSContext on the nsIThreadJSContextStack!\n"); |
|
994 else |
|
995 return xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps); |
|
996 |
|
997 return nullptr; |
|
998 } |
|
999 |
|
1000 /* void debugDumpEvalInJSStackFrame (in uint32_t aFrameNumber, in string aSourceText); */ |
|
1001 NS_IMETHODIMP |
|
1002 nsXPConnect::DebugDumpEvalInJSStackFrame(uint32_t aFrameNumber, const char *aSourceText) |
|
1003 { |
|
1004 JSContext* cx = GetCurrentJSContext(); |
|
1005 if (!cx) |
|
1006 printf("there is no JSContext on the nsIThreadJSContextStack!\n"); |
|
1007 else |
|
1008 xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText); |
|
1009 |
|
1010 return NS_OK; |
|
1011 } |
|
1012 |
|
1013 /* jsval variantToJS (in JSContextPtr ctx, in JSObjectPtr scope, in nsIVariant value); */ |
|
1014 NS_IMETHODIMP |
|
1015 nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg, nsIVariant* value, |
|
1016 MutableHandleValue _retval) |
|
1017 { |
|
1018 NS_PRECONDITION(ctx, "bad param"); |
|
1019 NS_PRECONDITION(scopeArg, "bad param"); |
|
1020 NS_PRECONDITION(value, "bad param"); |
|
1021 |
|
1022 RootedObject scope(ctx, scopeArg); |
|
1023 MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx)); |
|
1024 |
|
1025 nsresult rv = NS_OK; |
|
1026 if (!XPCVariant::VariantDataToJS(value, &rv, _retval)) { |
|
1027 if (NS_FAILED(rv)) |
|
1028 return rv; |
|
1029 |
|
1030 return NS_ERROR_FAILURE; |
|
1031 } |
|
1032 return NS_OK; |
|
1033 } |
|
1034 |
|
1035 /* nsIVariant JSToVariant (in JSContextPtr ctx, in jsval value); */ |
|
1036 NS_IMETHODIMP |
|
1037 nsXPConnect::JSToVariant(JSContext* ctx, HandleValue value, nsIVariant** _retval) |
|
1038 { |
|
1039 NS_PRECONDITION(ctx, "bad param"); |
|
1040 NS_PRECONDITION(_retval, "bad param"); |
|
1041 |
|
1042 nsRefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value); |
|
1043 variant.forget(_retval); |
|
1044 if (!(*_retval)) |
|
1045 return NS_ERROR_FAILURE; |
|
1046 |
|
1047 return NS_OK; |
|
1048 } |
|
1049 |
|
1050 NS_IMETHODIMP |
|
1051 nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait, |
|
1052 uint32_t aRecursionDepth) |
|
1053 { |
|
1054 // Record this event. |
|
1055 mEventDepth++; |
|
1056 |
|
1057 // Push a null JSContext so that we don't see any script during |
|
1058 // event processing. |
|
1059 MOZ_ASSERT(NS_IsMainThread()); |
|
1060 bool ok = PushJSContextNoScriptContext(nullptr); |
|
1061 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); |
|
1062 return NS_OK; |
|
1063 } |
|
1064 |
|
1065 NS_IMETHODIMP |
|
1066 nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread, |
|
1067 uint32_t aRecursionDepth, |
|
1068 bool aEventWasProcessed) |
|
1069 { |
|
1070 // Watch out for unpaired events during observer registration. |
|
1071 if (MOZ_UNLIKELY(mEventDepth == 0)) |
|
1072 return NS_OK; |
|
1073 mEventDepth--; |
|
1074 |
|
1075 // Now that we're back to the event loop, reset the slow script checkpoint. |
|
1076 mRuntime->OnAfterProcessNextEvent(); |
|
1077 |
|
1078 // Call cycle collector occasionally. |
|
1079 MOZ_ASSERT(NS_IsMainThread()); |
|
1080 nsJSContext::MaybePokeCC(); |
|
1081 nsDOMMutationObserver::HandleMutations(); |
|
1082 |
|
1083 PopJSContextNoScriptContext(); |
|
1084 |
|
1085 // If the cx stack is empty, that means we're at the an un-nested event |
|
1086 // loop. This is a good time to make changes to debug mode. |
|
1087 if (XPCJSRuntime::Get()->GetJSContextStack()->Count() == 0) { |
|
1088 MOZ_ASSERT(mEventDepth == 0); |
|
1089 CheckForDebugMode(XPCJSRuntime::Get()->Runtime()); |
|
1090 } |
|
1091 return NS_OK; |
|
1092 } |
|
1093 |
|
1094 NS_IMETHODIMP |
|
1095 nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread) |
|
1096 { |
|
1097 NS_NOTREACHED("Why tell us?"); |
|
1098 return NS_ERROR_UNEXPECTED; |
|
1099 } |
|
1100 |
|
1101 NS_IMETHODIMP |
|
1102 nsXPConnect::SetReportAllJSExceptions(bool newval) |
|
1103 { |
|
1104 // Ignore if the environment variable was set. |
|
1105 if (gReportAllJSExceptions != 1) |
|
1106 gReportAllJSExceptions = newval ? 2 : 0; |
|
1107 |
|
1108 return NS_OK; |
|
1109 } |
|
1110 |
|
1111 /* attribute JSRuntime runtime; */ |
|
1112 NS_IMETHODIMP |
|
1113 nsXPConnect::GetRuntime(JSRuntime **runtime) |
|
1114 { |
|
1115 if (!runtime) |
|
1116 return NS_ERROR_NULL_POINTER; |
|
1117 |
|
1118 JSRuntime *rt = GetRuntime()->Runtime(); |
|
1119 JS_AbortIfWrongThread(rt); |
|
1120 *runtime = rt; |
|
1121 return NS_OK; |
|
1122 } |
|
1123 |
|
1124 /* [noscript, notxpcom] void registerGCCallback(in xpcGCCallback func); */ |
|
1125 NS_IMETHODIMP_(void) |
|
1126 nsXPConnect::RegisterGCCallback(xpcGCCallback func) |
|
1127 { |
|
1128 mRuntime->AddGCCallback(func); |
|
1129 } |
|
1130 |
|
1131 /* [noscript, notxpcom] void unregisterGCCallback(in xpcGCCallback func); */ |
|
1132 NS_IMETHODIMP_(void) |
|
1133 nsXPConnect::UnregisterGCCallback(xpcGCCallback func) |
|
1134 { |
|
1135 mRuntime->RemoveGCCallback(func); |
|
1136 } |
|
1137 |
|
1138 /* [noscript, notxpcom] void registerContextCallback(in xpcContextCallback func); */ |
|
1139 NS_IMETHODIMP_(void) |
|
1140 nsXPConnect::RegisterContextCallback(xpcContextCallback func) |
|
1141 { |
|
1142 mRuntime->AddContextCallback(func); |
|
1143 } |
|
1144 |
|
1145 /* [noscript, notxpcom] void unregisterContextCallback(in xpcContextCallback func); */ |
|
1146 NS_IMETHODIMP_(void) |
|
1147 nsXPConnect::UnregisterContextCallback(xpcContextCallback func) |
|
1148 { |
|
1149 mRuntime->RemoveContextCallback(func); |
|
1150 } |
|
1151 |
|
1152 #ifdef MOZ_JSDEBUGGER |
|
1153 void |
|
1154 nsXPConnect::CheckForDebugMode(JSRuntime *rt) |
|
1155 { |
|
1156 if (gDebugMode == gDesiredDebugMode) { |
|
1157 return; |
|
1158 } |
|
1159 |
|
1160 // This can happen if a Worker is running, but we don't have the ability to |
|
1161 // debug workers right now, so just return. |
|
1162 if (!NS_IsMainThread()) |
|
1163 MOZ_CRASH(); |
|
1164 |
|
1165 AutoSafeJSContext cx; |
|
1166 JS_SetRuntimeDebugMode(rt, gDesiredDebugMode); |
|
1167 |
|
1168 nsresult rv; |
|
1169 const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1"; |
|
1170 nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv); |
|
1171 if (NS_FAILED(rv)) { |
|
1172 goto fail; |
|
1173 } |
|
1174 |
|
1175 if (!JS_SetDebugModeForAllCompartments(cx, gDesiredDebugMode)) |
|
1176 goto fail; |
|
1177 |
|
1178 if (gDesiredDebugMode) { |
|
1179 rv = jsds->ActivateDebugger(rt); |
|
1180 } |
|
1181 |
|
1182 gDebugMode = gDesiredDebugMode; |
|
1183 return; |
|
1184 |
|
1185 fail: |
|
1186 if (jsds) |
|
1187 jsds->DeactivateDebugger(); |
|
1188 |
|
1189 /* |
|
1190 * If an attempt to turn debug mode on fails, cancel the request. It's |
|
1191 * always safe to turn debug mode off, since DeactivateDebugger prevents |
|
1192 * debugger callbacks from having any effect. |
|
1193 */ |
|
1194 if (gDesiredDebugMode) |
|
1195 JS_SetRuntimeDebugMode(rt, false); |
|
1196 gDesiredDebugMode = gDebugMode = false; |
|
1197 } |
|
1198 #else //MOZ_JSDEBUGGER not defined |
|
1199 void |
|
1200 nsXPConnect::CheckForDebugMode(JSRuntime *rt) |
|
1201 { |
|
1202 gDesiredDebugMode = gDebugMode = false; |
|
1203 } |
|
1204 #endif //#ifdef MOZ_JSDEBUGGER |
|
1205 |
|
1206 |
|
1207 void |
|
1208 xpc_ActivateDebugMode() |
|
1209 { |
|
1210 XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); |
|
1211 nsXPConnect::XPConnect()->SetDebugModeWhenPossible(true, true); |
|
1212 nsXPConnect::CheckForDebugMode(rt->Runtime()); |
|
1213 } |
|
1214 |
|
1215 /* virtual */ |
|
1216 JSContext* |
|
1217 nsXPConnect::GetCurrentJSContext() |
|
1218 { |
|
1219 return GetRuntime()->GetJSContextStack()->Peek(); |
|
1220 } |
|
1221 |
|
1222 /* virtual */ |
|
1223 JSContext* |
|
1224 nsXPConnect::InitSafeJSContext() |
|
1225 { |
|
1226 return GetRuntime()->GetJSContextStack()->InitSafeJSContext(); |
|
1227 } |
|
1228 |
|
1229 /* virtual */ |
|
1230 JSContext* |
|
1231 nsXPConnect::GetSafeJSContext() |
|
1232 { |
|
1233 return GetRuntime()->GetJSContextStack()->GetSafeJSContext(); |
|
1234 } |
|
1235 |
|
1236 namespace xpc { |
|
1237 |
|
1238 bool |
|
1239 PushJSContextNoScriptContext(JSContext *aCx) |
|
1240 { |
|
1241 MOZ_ASSERT_IF(aCx, !GetScriptContextFromJSContext(aCx)); |
|
1242 return XPCJSRuntime::Get()->GetJSContextStack()->Push(aCx); |
|
1243 } |
|
1244 |
|
1245 void |
|
1246 PopJSContextNoScriptContext() |
|
1247 { |
|
1248 XPCJSRuntime::Get()->GetJSContextStack()->Pop(); |
|
1249 } |
|
1250 |
|
1251 } // namespace xpc |
|
1252 |
|
1253 nsIPrincipal* |
|
1254 nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const |
|
1255 { |
|
1256 MOZ_ASSERT(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?"); |
|
1257 |
|
1258 XPCWrappedNative *xpcWrapper = XPCWrappedNative::Get(obj); |
|
1259 if (xpcWrapper) { |
|
1260 if (allowShortCircuit) { |
|
1261 nsIPrincipal *result = xpcWrapper->GetObjectPrincipal(); |
|
1262 if (result) { |
|
1263 return result; |
|
1264 } |
|
1265 } |
|
1266 |
|
1267 // If not, check if it points to an nsIScriptObjectPrincipal |
|
1268 nsCOMPtr<nsIScriptObjectPrincipal> objPrin = |
|
1269 do_QueryInterface(xpcWrapper->Native()); |
|
1270 if (objPrin) { |
|
1271 nsIPrincipal *result = objPrin->GetPrincipal(); |
|
1272 if (result) { |
|
1273 return result; |
|
1274 } |
|
1275 } |
|
1276 } |
|
1277 |
|
1278 return nullptr; |
|
1279 } |
|
1280 |
|
1281 NS_IMETHODIMP |
|
1282 nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObjectArg, |
|
1283 nsIXPConnectJSObjectHolder **aHolder) |
|
1284 { |
|
1285 RootedObject aObject(aJSContext, aObjectArg); |
|
1286 XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(aObject); |
|
1287 if (!objHolder) |
|
1288 return NS_ERROR_OUT_OF_MEMORY; |
|
1289 |
|
1290 NS_ADDREF(*aHolder = objHolder); |
|
1291 return NS_OK; |
|
1292 } |
|
1293 |
|
1294 namespace xpc { |
|
1295 |
|
1296 bool |
|
1297 Base64Encode(JSContext *cx, HandleValue val, MutableHandleValue out) |
|
1298 { |
|
1299 MOZ_ASSERT(cx); |
|
1300 |
|
1301 JS::RootedValue root(cx, val); |
|
1302 xpc_qsACString encodedString(cx, root, &root, false, |
|
1303 xpc_qsACString::eStringify, |
|
1304 xpc_qsACString::eStringify); |
|
1305 if (!encodedString.IsValid()) |
|
1306 return false; |
|
1307 |
|
1308 nsAutoCString result; |
|
1309 if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) { |
|
1310 JS_ReportError(cx, "Failed to encode base64 data!"); |
|
1311 return false; |
|
1312 } |
|
1313 |
|
1314 JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length()); |
|
1315 if (!str) |
|
1316 return false; |
|
1317 |
|
1318 out.setString(str); |
|
1319 return true; |
|
1320 } |
|
1321 |
|
1322 bool |
|
1323 Base64Decode(JSContext *cx, HandleValue val, MutableHandleValue out) |
|
1324 { |
|
1325 MOZ_ASSERT(cx); |
|
1326 |
|
1327 JS::RootedValue root(cx, val); |
|
1328 xpc_qsACString encodedString(cx, root, &root, false, |
|
1329 xpc_qsACString::eStringify, |
|
1330 xpc_qsACString::eStringify); |
|
1331 if (!encodedString.IsValid()) |
|
1332 return false; |
|
1333 |
|
1334 nsAutoCString result; |
|
1335 if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) { |
|
1336 JS_ReportError(cx, "Failed to decode base64 string!"); |
|
1337 return false; |
|
1338 } |
|
1339 |
|
1340 JSString *str = JS_NewStringCopyN(cx, result.get(), result.Length()); |
|
1341 if (!str) |
|
1342 return false; |
|
1343 |
|
1344 out.setString(str); |
|
1345 return true; |
|
1346 } |
|
1347 |
|
1348 void |
|
1349 SetLocationForGlobal(JSObject *global, const nsACString& location) |
|
1350 { |
|
1351 MOZ_ASSERT(global); |
|
1352 EnsureCompartmentPrivate(global)->SetLocation(location); |
|
1353 } |
|
1354 |
|
1355 void |
|
1356 SetLocationForGlobal(JSObject *global, nsIURI *locationURI) |
|
1357 { |
|
1358 MOZ_ASSERT(global); |
|
1359 EnsureCompartmentPrivate(global)->SetLocationURI(locationURI); |
|
1360 } |
|
1361 |
|
1362 } // namespace xpc |
|
1363 |
|
1364 NS_IMETHODIMP |
|
1365 nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable) |
|
1366 { |
|
1367 gDesiredDebugMode = mode; |
|
1368 if (!mode && allowSyncDisable) |
|
1369 CheckForDebugMode(mRuntime->Runtime()); |
|
1370 return NS_OK; |
|
1371 } |
|
1372 |
|
1373 NS_IMETHODIMP |
|
1374 nsXPConnect::NotifyDidPaint() |
|
1375 { |
|
1376 JS::NotifyDidPaint(GetRuntime()->Runtime()); |
|
1377 return NS_OK; |
|
1378 } |
|
1379 |
|
1380 // Note - We used to have HAS_PRINCIPALS_FLAG = 1 here, so reusing that flag |
|
1381 // will require bumping the XDR version number. |
|
1382 static const uint8_t HAS_ORIGIN_PRINCIPALS_FLAG = 2; |
|
1383 |
|
1384 static nsresult |
|
1385 WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx, |
|
1386 JSScript *scriptArg, HandleObject functionObj) |
|
1387 { |
|
1388 // Exactly one of script or functionObj must be given |
|
1389 MOZ_ASSERT(!scriptArg != !functionObj); |
|
1390 |
|
1391 RootedScript script(cx, scriptArg); |
|
1392 if (!script) { |
|
1393 RootedFunction fun(cx, JS_GetObjectFunction(functionObj)); |
|
1394 script.set(JS_GetFunctionScript(cx, fun)); |
|
1395 } |
|
1396 |
|
1397 nsIPrincipal *principal = |
|
1398 nsJSPrincipals::get(JS_GetScriptPrincipals(script)); |
|
1399 nsIPrincipal *originPrincipal = |
|
1400 nsJSPrincipals::get(JS_GetScriptOriginPrincipals(script)); |
|
1401 |
|
1402 uint8_t flags = 0; |
|
1403 |
|
1404 // Optimize for the common case when originPrincipals == principals. As |
|
1405 // originPrincipals is set to principals when the former is null we can |
|
1406 // simply skip the originPrincipals when they are the same as principals. |
|
1407 if (originPrincipal && originPrincipal != principal) |
|
1408 flags |= HAS_ORIGIN_PRINCIPALS_FLAG; |
|
1409 |
|
1410 nsresult rv = stream->Write8(flags); |
|
1411 if (NS_FAILED(rv)) |
|
1412 return rv; |
|
1413 |
|
1414 if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) { |
|
1415 rv = stream->WriteObject(originPrincipal, true); |
|
1416 if (NS_FAILED(rv)) |
|
1417 return rv; |
|
1418 } |
|
1419 |
|
1420 uint32_t size; |
|
1421 void* data; |
|
1422 { |
|
1423 if (functionObj) |
|
1424 data = JS_EncodeInterpretedFunction(cx, functionObj, &size); |
|
1425 else |
|
1426 data = JS_EncodeScript(cx, script, &size); |
|
1427 } |
|
1428 |
|
1429 if (!data) |
|
1430 return NS_ERROR_OUT_OF_MEMORY; |
|
1431 MOZ_ASSERT(size); |
|
1432 rv = stream->Write32(size); |
|
1433 if (NS_SUCCEEDED(rv)) |
|
1434 rv = stream->WriteBytes(static_cast<char *>(data), size); |
|
1435 js_free(data); |
|
1436 |
|
1437 return rv; |
|
1438 } |
|
1439 |
|
1440 static nsresult |
|
1441 ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx, |
|
1442 JSScript **scriptp, JSObject **functionObjp) |
|
1443 { |
|
1444 // Exactly one of script or functionObj must be given |
|
1445 MOZ_ASSERT(!scriptp != !functionObjp); |
|
1446 |
|
1447 uint8_t flags; |
|
1448 nsresult rv = stream->Read8(&flags); |
|
1449 if (NS_FAILED(rv)) |
|
1450 return rv; |
|
1451 |
|
1452 nsJSPrincipals* originPrincipal = nullptr; |
|
1453 nsCOMPtr<nsIPrincipal> readOriginPrincipal; |
|
1454 if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) { |
|
1455 nsCOMPtr<nsISupports> supports; |
|
1456 rv = stream->ReadObject(true, getter_AddRefs(supports)); |
|
1457 if (NS_FAILED(rv)) |
|
1458 return rv; |
|
1459 readOriginPrincipal = do_QueryInterface(supports); |
|
1460 originPrincipal = nsJSPrincipals::get(readOriginPrincipal); |
|
1461 } |
|
1462 |
|
1463 uint32_t size; |
|
1464 rv = stream->Read32(&size); |
|
1465 if (NS_FAILED(rv)) |
|
1466 return rv; |
|
1467 |
|
1468 char* data; |
|
1469 rv = stream->ReadBytes(size, &data); |
|
1470 if (NS_FAILED(rv)) |
|
1471 return rv; |
|
1472 |
|
1473 { |
|
1474 if (scriptp) { |
|
1475 JSScript *script = JS_DecodeScript(cx, data, size, originPrincipal); |
|
1476 if (!script) |
|
1477 rv = NS_ERROR_OUT_OF_MEMORY; |
|
1478 else |
|
1479 *scriptp = script; |
|
1480 } else { |
|
1481 JSObject *funobj = JS_DecodeInterpretedFunction(cx, data, size, |
|
1482 originPrincipal); |
|
1483 if (!funobj) |
|
1484 rv = NS_ERROR_OUT_OF_MEMORY; |
|
1485 else |
|
1486 *functionObjp = funobj; |
|
1487 } |
|
1488 } |
|
1489 |
|
1490 nsMemory::Free(data); |
|
1491 return rv; |
|
1492 } |
|
1493 |
|
1494 NS_IMETHODIMP |
|
1495 nsXPConnect::WriteScript(nsIObjectOutputStream *stream, JSContext *cx, JSScript *script) |
|
1496 { |
|
1497 return WriteScriptOrFunction(stream, cx, script, NullPtr()); |
|
1498 } |
|
1499 |
|
1500 NS_IMETHODIMP |
|
1501 nsXPConnect::ReadScript(nsIObjectInputStream *stream, JSContext *cx, JSScript **scriptp) |
|
1502 { |
|
1503 return ReadScriptOrFunction(stream, cx, scriptp, nullptr); |
|
1504 } |
|
1505 |
|
1506 NS_IMETHODIMP |
|
1507 nsXPConnect::WriteFunction(nsIObjectOutputStream *stream, JSContext *cx, JSObject *functionObjArg) |
|
1508 { |
|
1509 RootedObject functionObj(cx, functionObjArg); |
|
1510 return WriteScriptOrFunction(stream, cx, nullptr, functionObj); |
|
1511 } |
|
1512 |
|
1513 NS_IMETHODIMP |
|
1514 nsXPConnect::ReadFunction(nsIObjectInputStream *stream, JSContext *cx, JSObject **functionObjp) |
|
1515 { |
|
1516 return ReadScriptOrFunction(stream, cx, nullptr, functionObjp); |
|
1517 } |
|
1518 |
|
1519 NS_IMETHODIMP |
|
1520 nsXPConnect::MarkErrorUnreported(JSContext *cx) |
|
1521 { |
|
1522 XPCContext *xpcc = XPCContext::GetXPCContext(cx); |
|
1523 xpcc->MarkErrorUnreported(); |
|
1524 return NS_OK; |
|
1525 } |
|
1526 |
|
1527 /* These are here to be callable from a debugger */ |
|
1528 extern "C" { |
|
1529 JS_EXPORT_API(void) DumpJSStack() |
|
1530 { |
|
1531 nsresult rv; |
|
1532 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); |
|
1533 if (NS_SUCCEEDED(rv) && xpc) |
|
1534 xpc->DebugDumpJSStack(true, true, false); |
|
1535 else |
|
1536 printf("failed to get XPConnect service!\n"); |
|
1537 } |
|
1538 |
|
1539 JS_EXPORT_API(char*) PrintJSStack() |
|
1540 { |
|
1541 nsresult rv; |
|
1542 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); |
|
1543 return (NS_SUCCEEDED(rv) && xpc) ? |
|
1544 xpc->DebugPrintJSStack(true, true, false) : |
|
1545 nullptr; |
|
1546 } |
|
1547 |
|
1548 JS_EXPORT_API(void) DumpJSEval(uint32_t frameno, const char* text) |
|
1549 { |
|
1550 nsresult rv; |
|
1551 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); |
|
1552 if (NS_SUCCEEDED(rv) && xpc) |
|
1553 xpc->DebugDumpEvalInJSStackFrame(frameno, text); |
|
1554 else |
|
1555 printf("failed to get XPConnect service!\n"); |
|
1556 } |
|
1557 |
|
1558 JS_EXPORT_API(void) DumpCompleteHeap() |
|
1559 { |
|
1560 nsCOMPtr<nsICycleCollectorListener> listener = |
|
1561 do_CreateInstance("@mozilla.org/cycle-collector-logger;1"); |
|
1562 if (!listener) { |
|
1563 NS_WARNING("Failed to create CC logger"); |
|
1564 return; |
|
1565 } |
|
1566 |
|
1567 nsCOMPtr<nsICycleCollectorListener> alltracesListener; |
|
1568 listener->AllTraces(getter_AddRefs(alltracesListener)); |
|
1569 if (!alltracesListener) { |
|
1570 NS_WARNING("Failed to get all traces logger"); |
|
1571 return; |
|
1572 } |
|
1573 |
|
1574 nsJSContext::CycleCollectNow(alltracesListener); |
|
1575 } |
|
1576 |
|
1577 } // extern "C" |
|
1578 |
|
1579 namespace xpc { |
|
1580 |
|
1581 bool |
|
1582 Atob(JSContext *cx, unsigned argc, Value *vp) |
|
1583 { |
|
1584 CallArgs args = CallArgsFromVp(argc, vp); |
|
1585 if (!args.length()) |
|
1586 return true; |
|
1587 |
|
1588 return xpc::Base64Decode(cx, args[0], args.rval()); |
|
1589 } |
|
1590 |
|
1591 bool |
|
1592 Btoa(JSContext *cx, unsigned argc, Value *vp) |
|
1593 { |
|
1594 CallArgs args = CallArgsFromVp(argc, vp); |
|
1595 if (!args.length()) |
|
1596 return true; |
|
1597 |
|
1598 return xpc::Base64Encode(cx, args[0], args.rval()); |
|
1599 } |
|
1600 |
|
1601 bool |
|
1602 IsXrayWrapper(JSObject *obj) |
|
1603 { |
|
1604 return WrapperFactory::IsXrayWrapper(obj); |
|
1605 } |
|
1606 |
|
1607 } // namespace xpc |
|
1608 |
|
1609 namespace mozilla { |
|
1610 namespace dom { |
|
1611 |
|
1612 bool |
|
1613 IsChromeOrXBL(JSContext* cx, JSObject* /* unused */) |
|
1614 { |
|
1615 MOZ_ASSERT(NS_IsMainThread()); |
|
1616 JSCompartment* c = js::GetContextCompartment(cx); |
|
1617 |
|
1618 // For remote XUL, we run XBL in the XUL scope. Given that we care about |
|
1619 // compat and not security for remote XUL, we just always claim to be XBL. |
|
1620 // |
|
1621 // Note that, for performance, we don't check AllowXULXBLForPrincipal here, |
|
1622 // and instead rely on the fact that AllowXBLScope() only returns false in |
|
1623 // remote XUL situations. |
|
1624 return AccessCheck::isChrome(c) || IsXBLScope(c) || !AllowXBLScope(c); |
|
1625 } |
|
1626 |
|
1627 } // namespace dom |
|
1628 } // namespace mozilla |