Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
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 |