js/xpconnect/src/nsXPConnect.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial