1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,589 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozJSSubScriptLoader.h" 1.11 +#include "mozJSComponentLoader.h" 1.12 +#include "mozJSLoaderUtils.h" 1.13 + 1.14 +#include "nsIURI.h" 1.15 +#include "nsIIOService.h" 1.16 +#include "nsIChannel.h" 1.17 +#include "nsIInputStream.h" 1.18 +#include "nsNetCID.h" 1.19 +#include "nsNetUtil.h" 1.20 +#include "nsIFileURL.h" 1.21 +#include "nsScriptLoader.h" 1.22 +#include "nsIScriptSecurityManager.h" 1.23 +#include "nsThreadUtils.h" 1.24 + 1.25 +#include "jsapi.h" 1.26 +#include "jsfriendapi.h" 1.27 +#include "js/OldDebugAPI.h" 1.28 +#include "nsJSPrincipals.h" 1.29 +#include "xpcpublic.h" // For xpc::SystemErrorReporter 1.30 +#include "xpcprivate.h" // For xpc::OptionsBase 1.31 +#include "jswrapper.h" 1.32 + 1.33 +#include "mozilla/scache/StartupCache.h" 1.34 +#include "mozilla/scache/StartupCacheUtils.h" 1.35 +#include "mozilla/unused.h" 1.36 + 1.37 +using namespace mozilla::scache; 1.38 +using namespace JS; 1.39 +using namespace xpc; 1.40 +using namespace mozilla; 1.41 + 1.42 +class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase { 1.43 +public: 1.44 + LoadSubScriptOptions(JSContext *cx = xpc_GetSafeJSContext(), 1.45 + JSObject *options = nullptr) 1.46 + : OptionsBase(cx, options) 1.47 + , target(cx) 1.48 + , charset(NullString()) 1.49 + , ignoreCache(false) 1.50 + { } 1.51 + 1.52 + virtual bool Parse() { 1.53 + return ParseObject("target", &target) && 1.54 + ParseString("charset", charset) && 1.55 + ParseBoolean("ignoreCache", &ignoreCache); 1.56 + } 1.57 + 1.58 + RootedObject target; 1.59 + nsString charset; 1.60 + bool ignoreCache; 1.61 +}; 1.62 + 1.63 + 1.64 +/* load() error msgs, XXX localize? */ 1.65 +#define LOAD_ERROR_NOSERVICE "Error creating IO Service." 1.66 +#define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)" 1.67 +#define LOAD_ERROR_NOSCHEME "Failed to get URI scheme. This is bad." 1.68 +#define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI." 1.69 +#define LOAD_ERROR_NOSTREAM "Error opening input stream (invalid filename?)" 1.70 +#define LOAD_ERROR_NOCONTENT "ContentLength not available (not a local URL?)" 1.71 +#define LOAD_ERROR_BADCHARSET "Error converting to specified charset" 1.72 +#define LOAD_ERROR_BADREAD "File Read Error." 1.73 +#define LOAD_ERROR_READUNDERFLOW "File Read Error (underflow.)" 1.74 +#define LOAD_ERROR_NOPRINCIPALS "Failed to get principals." 1.75 +#define LOAD_ERROR_NOSPEC "Failed to get URI spec. This is bad." 1.76 +#define LOAD_ERROR_CONTENTTOOBIG "ContentLength is too large" 1.77 + 1.78 +mozJSSubScriptLoader::mozJSSubScriptLoader() : mSystemPrincipal(nullptr) 1.79 +{ 1.80 + // Force construction of the JS component loader. We may need it later. 1.81 + nsCOMPtr<xpcIJSModuleLoader> componentLoader = 1.82 + do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); 1.83 +} 1.84 + 1.85 +mozJSSubScriptLoader::~mozJSSubScriptLoader() 1.86 +{ 1.87 + /* empty */ 1.88 +} 1.89 + 1.90 +NS_IMPL_ISUPPORTS(mozJSSubScriptLoader, mozIJSSubScriptLoader) 1.91 + 1.92 +static nsresult 1.93 +ReportError(JSContext *cx, const char *msg) 1.94 +{ 1.95 + RootedValue exn(cx, JS::StringValue(JS_NewStringCopyZ(cx, msg))); 1.96 + JS_SetPendingException(cx, exn); 1.97 + return NS_OK; 1.98 +} 1.99 + 1.100 +nsresult 1.101 +mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObjArg, 1.102 + const nsAString &charset, const char *uriStr, 1.103 + nsIIOService *serv, nsIPrincipal *principal, 1.104 + bool reuseGlobal, JS::MutableHandleScript script, 1.105 + JS::MutableHandleFunction function) 1.106 +{ 1.107 + RootedObject target_obj(cx, targetObjArg); 1.108 + 1.109 + script.set(nullptr); 1.110 + function.set(nullptr); 1.111 + 1.112 + // Instead of calling NS_OpenURI, we create the channel ourselves and call 1.113 + // SetContentType, to avoid expensive MIME type lookups (bug 632490). 1.114 + nsCOMPtr<nsIChannel> chan; 1.115 + nsCOMPtr<nsIInputStream> instream; 1.116 + nsresult rv = NS_NewChannel(getter_AddRefs(chan), uri, serv, 1.117 + nullptr, nullptr, nsIRequest::LOAD_NORMAL); 1.118 + if (NS_SUCCEEDED(rv)) { 1.119 + chan->SetContentType(NS_LITERAL_CSTRING("application/javascript")); 1.120 + rv = chan->Open(getter_AddRefs(instream)); 1.121 + } 1.122 + 1.123 + if (NS_FAILED(rv)) { 1.124 + return ReportError(cx, LOAD_ERROR_NOSTREAM); 1.125 + } 1.126 + 1.127 + int64_t len = -1; 1.128 + 1.129 + rv = chan->GetContentLength(&len); 1.130 + if (NS_FAILED(rv) || len == -1) { 1.131 + return ReportError(cx, LOAD_ERROR_NOCONTENT); 1.132 + } 1.133 + 1.134 + if (len > INT32_MAX) { 1.135 + return ReportError(cx, LOAD_ERROR_CONTENTTOOBIG); 1.136 + } 1.137 + 1.138 + nsCString buf; 1.139 + rv = NS_ReadInputStreamToString(instream, buf, len); 1.140 + if (NS_FAILED(rv)) 1.141 + return rv; 1.142 + 1.143 + /* set our own error reporter so we can report any bad things as catchable 1.144 + * exceptions, including the source/line number */ 1.145 + JSErrorReporter er = JS_SetErrorReporter(cx, xpc::SystemErrorReporter); 1.146 + 1.147 + JS::CompileOptions options(cx); 1.148 + options.setFileAndLine(uriStr, 1); 1.149 + if (!charset.IsVoid()) { 1.150 + jschar *scriptBuf = nullptr; 1.151 + size_t scriptLength = 0; 1.152 + 1.153 + rv = nsScriptLoader::ConvertToUTF16(nullptr, reinterpret_cast<const uint8_t*>(buf.get()), len, 1.154 + charset, nullptr, scriptBuf, scriptLength); 1.155 + 1.156 + JS::SourceBufferHolder srcBuf(scriptBuf, scriptLength, 1.157 + JS::SourceBufferHolder::GiveOwnership); 1.158 + 1.159 + if (NS_FAILED(rv)) { 1.160 + return ReportError(cx, LOAD_ERROR_BADCHARSET); 1.161 + } 1.162 + 1.163 + if (!reuseGlobal) { 1.164 + JS::Compile(cx, target_obj, options, srcBuf, script); 1.165 + } else { 1.166 + JS::CompileFunction(cx, target_obj, options, 1.167 + nullptr, 0, nullptr, 1.168 + srcBuf, 1.169 + function); 1.170 + } 1.171 + } else { 1.172 + // We only use lazy source when no special encoding is specified because 1.173 + // the lazy source loader doesn't know the encoding. 1.174 + if (!reuseGlobal) { 1.175 + options.setSourceIsLazy(true); 1.176 + script.set(JS::Compile(cx, target_obj, options, buf.get(), len)); 1.177 + } else { 1.178 + function.set(JS::CompileFunction(cx, target_obj, options, 1.179 + nullptr, 0, nullptr, buf.get(), 1.180 + len)); 1.181 + } 1.182 + } 1.183 + 1.184 + /* repent for our evil deeds */ 1.185 + JS_SetErrorReporter(cx, er); 1.186 + 1.187 + return NS_OK; 1.188 +} 1.189 + 1.190 +NS_IMETHODIMP 1.191 +mozJSSubScriptLoader::LoadSubScript(const nsAString &url, 1.192 + HandleValue target, 1.193 + const nsAString &charset, 1.194 + JSContext *cx, 1.195 + MutableHandleValue retval) 1.196 +{ 1.197 + /* 1.198 + * Loads a local url and evals it into the current cx 1.199 + * Synchronous (an async version would be cool too.) 1.200 + * url: The url to load. Must be local so that it can be loaded 1.201 + * synchronously. 1.202 + * target_obj: Optional object to eval the script onto (defaults to context 1.203 + * global) 1.204 + * charset: Optional character set to use for reading 1.205 + * returns: Whatever jsval the script pointed to by the url returns. 1.206 + * Should ONLY (O N L Y !) be called from JavaScript code. 1.207 + */ 1.208 + LoadSubScriptOptions options(cx); 1.209 + options.charset = charset; 1.210 + options.target = target.isObject() ? &target.toObject() : nullptr; 1.211 + return DoLoadSubScriptWithOptions(url, options, cx, retval); 1.212 +} 1.213 + 1.214 + 1.215 +NS_IMETHODIMP 1.216 +mozJSSubScriptLoader::LoadSubScriptWithOptions(const nsAString &url, 1.217 + HandleValue optionsVal, 1.218 + JSContext *cx, 1.219 + MutableHandleValue retval) 1.220 +{ 1.221 + if (!optionsVal.isObject()) 1.222 + return NS_ERROR_INVALID_ARG; 1.223 + LoadSubScriptOptions options(cx, &optionsVal.toObject()); 1.224 + if (!options.Parse()) 1.225 + return NS_ERROR_INVALID_ARG; 1.226 + return DoLoadSubScriptWithOptions(url, options, cx, retval); 1.227 +} 1.228 + 1.229 +nsresult 1.230 +mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url, 1.231 + LoadSubScriptOptions &options, 1.232 + JSContext *cx, 1.233 + MutableHandleValue retval) 1.234 +{ 1.235 + nsresult rv = NS_OK; 1.236 + 1.237 + /* set the system principal if it's not here already */ 1.238 + if (!mSystemPrincipal) { 1.239 + nsCOMPtr<nsIScriptSecurityManager> secman = 1.240 + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); 1.241 + if (!secman) 1.242 + return NS_OK; 1.243 + 1.244 + rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal)); 1.245 + if (NS_FAILED(rv) || !mSystemPrincipal) 1.246 + return rv; 1.247 + } 1.248 + 1.249 + RootedObject targetObj(cx); 1.250 + mozJSComponentLoader *loader = mozJSComponentLoader::Get(); 1.251 + rv = loader->FindTargetObject(cx, &targetObj); 1.252 + NS_ENSURE_SUCCESS(rv, rv); 1.253 + 1.254 + // We base reusingGlobal off of what the loader told us, but we may not 1.255 + // actually be using that object. 1.256 + bool reusingGlobal = !JS_IsGlobalObject(targetObj); 1.257 + 1.258 + if (options.target) 1.259 + targetObj = options.target; 1.260 + 1.261 + // Remember an object out of the calling compartment so that we 1.262 + // can properly wrap the result later. 1.263 + nsCOMPtr<nsIPrincipal> principal = mSystemPrincipal; 1.264 + RootedObject result_obj(cx, targetObj); 1.265 + targetObj = JS_FindCompilationScope(cx, targetObj); 1.266 + if (!targetObj) 1.267 + return NS_ERROR_FAILURE; 1.268 + 1.269 + if (targetObj != result_obj) 1.270 + principal = GetObjectPrincipal(targetObj); 1.271 + 1.272 + JSAutoCompartment ac(cx, targetObj); 1.273 + 1.274 + /* load up the url. From here on, failures are reflected as ``custom'' 1.275 + * js exceptions */ 1.276 + nsCOMPtr<nsIURI> uri; 1.277 + nsAutoCString uriStr; 1.278 + nsAutoCString scheme; 1.279 + 1.280 + // Figure out who's calling us 1.281 + JS::AutoFilename filename; 1.282 + if (!JS::DescribeScriptedCaller(cx, &filename)) { 1.283 + // No scripted frame means we don't know who's calling, bail. 1.284 + return NS_ERROR_FAILURE; 1.285 + } 1.286 + 1.287 + // Suppress caching if we're compiling as content. 1.288 + StartupCache* cache = (principal == mSystemPrincipal) 1.289 + ? StartupCache::GetSingleton() 1.290 + : nullptr; 1.291 + nsCOMPtr<nsIIOService> serv = do_GetService(NS_IOSERVICE_CONTRACTID); 1.292 + if (!serv) { 1.293 + return ReportError(cx, LOAD_ERROR_NOSERVICE); 1.294 + } 1.295 + 1.296 + // Make sure to explicitly create the URI, since we'll need the 1.297 + // canonicalized spec. 1.298 + rv = NS_NewURI(getter_AddRefs(uri), NS_LossyConvertUTF16toASCII(url).get(), nullptr, serv); 1.299 + if (NS_FAILED(rv)) { 1.300 + return ReportError(cx, LOAD_ERROR_NOURI); 1.301 + } 1.302 + 1.303 + rv = uri->GetSpec(uriStr); 1.304 + if (NS_FAILED(rv)) { 1.305 + return ReportError(cx, LOAD_ERROR_NOSPEC); 1.306 + } 1.307 + 1.308 + rv = uri->GetScheme(scheme); 1.309 + if (NS_FAILED(rv)) { 1.310 + return ReportError(cx, LOAD_ERROR_NOSCHEME); 1.311 + } 1.312 + 1.313 + if (!scheme.EqualsLiteral("chrome")) { 1.314 + // This might be a URI to a local file, though! 1.315 + nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri); 1.316 + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(innerURI); 1.317 + if (!fileURL) { 1.318 + return ReportError(cx, LOAD_ERROR_URI_NOT_LOCAL); 1.319 + } 1.320 + 1.321 + // For file URIs prepend the filename with the filename of the 1.322 + // calling script, and " -> ". See bug 418356. 1.323 + nsAutoCString tmp(filename.get()); 1.324 + tmp.AppendLiteral(" -> "); 1.325 + tmp.Append(uriStr); 1.326 + 1.327 + uriStr = tmp; 1.328 + } 1.329 + 1.330 + bool writeScript = false; 1.331 + JSVersion version = JS_GetVersion(cx); 1.332 + nsAutoCString cachePath; 1.333 + cachePath.AppendPrintf("jssubloader/%d", version); 1.334 + PathifyURI(uri, cachePath); 1.335 + 1.336 + RootedFunction function(cx); 1.337 + RootedScript script(cx); 1.338 + if (cache && !options.ignoreCache) 1.339 + rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script); 1.340 + if (!script) { 1.341 + rv = ReadScript(uri, cx, targetObj, options.charset, 1.342 + static_cast<const char*>(uriStr.get()), serv, 1.343 + principal, reusingGlobal, &script, &function); 1.344 + writeScript = !!script; 1.345 + } 1.346 + 1.347 + if (NS_FAILED(rv) || (!script && !function)) 1.348 + return rv; 1.349 + 1.350 + if (function) { 1.351 + script = JS_GetFunctionScript(cx, function); 1.352 + } 1.353 + 1.354 + loader->NoteSubScript(script, targetObj); 1.355 + 1.356 + 1.357 + bool ok = false; 1.358 + if (function) { 1.359 + ok = JS_CallFunction(cx, targetObj, function, JS::HandleValueArray::empty(), 1.360 + retval); 1.361 + } else { 1.362 + ok = JS_ExecuteScriptVersion(cx, targetObj, script, retval, version); 1.363 + } 1.364 + 1.365 + if (ok) { 1.366 + JSAutoCompartment rac(cx, result_obj); 1.367 + if (!JS_WrapValue(cx, retval)) 1.368 + return NS_ERROR_UNEXPECTED; 1.369 + } 1.370 + 1.371 + if (cache && ok && writeScript) { 1.372 + WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script); 1.373 + } 1.374 + 1.375 + return NS_OK; 1.376 +} 1.377 + 1.378 +/** 1.379 + * Let us compile scripts from a URI off the main thread. 1.380 + */ 1.381 + 1.382 +class ScriptPrecompiler : public nsIStreamLoaderObserver 1.383 +{ 1.384 +public: 1.385 + NS_DECL_ISUPPORTS 1.386 + NS_DECL_NSISTREAMLOADEROBSERVER 1.387 + 1.388 + ScriptPrecompiler(nsIObserver* aObserver, 1.389 + nsIPrincipal* aPrincipal, 1.390 + nsIChannel* aChannel) 1.391 + : mObserver(aObserver) 1.392 + , mPrincipal(aPrincipal) 1.393 + , mChannel(aChannel) 1.394 + , mScriptBuf(nullptr) 1.395 + , mScriptLength(0) 1.396 + {} 1.397 + 1.398 + virtual ~ScriptPrecompiler() 1.399 + { 1.400 + if (mScriptBuf) { 1.401 + js_free(mScriptBuf); 1.402 + } 1.403 + } 1.404 + 1.405 + static void OffThreadCallback(void *aToken, void *aData); 1.406 + 1.407 + /* Sends the "done" notification back. Main thread only. */ 1.408 + void SendObserverNotification(); 1.409 + 1.410 +private: 1.411 + nsRefPtr<nsIObserver> mObserver; 1.412 + nsRefPtr<nsIPrincipal> mPrincipal; 1.413 + nsRefPtr<nsIChannel> mChannel; 1.414 + jschar* mScriptBuf; 1.415 + size_t mScriptLength; 1.416 +}; 1.417 + 1.418 +NS_IMPL_ISUPPORTS(ScriptPrecompiler, nsIStreamLoaderObserver); 1.419 + 1.420 +class NotifyPrecompilationCompleteRunnable : public nsRunnable 1.421 +{ 1.422 +public: 1.423 + NS_DECL_NSIRUNNABLE 1.424 + 1.425 + NotifyPrecompilationCompleteRunnable(ScriptPrecompiler* aPrecompiler) 1.426 + : mPrecompiler(aPrecompiler) 1.427 + , mToken(nullptr) 1.428 + {} 1.429 + 1.430 + void SetToken(void* aToken) { 1.431 + MOZ_ASSERT(aToken && !mToken); 1.432 + mToken = aToken; 1.433 + } 1.434 + 1.435 +protected: 1.436 + nsRefPtr<ScriptPrecompiler> mPrecompiler; 1.437 + void* mToken; 1.438 +}; 1.439 + 1.440 +/* RAII helper class to send observer notifications */ 1.441 +class AutoSendObserverNotification { 1.442 +public: 1.443 + AutoSendObserverNotification(ScriptPrecompiler* aPrecompiler) 1.444 + : mPrecompiler(aPrecompiler) 1.445 + {} 1.446 + 1.447 + ~AutoSendObserverNotification() { 1.448 + if (mPrecompiler) { 1.449 + mPrecompiler->SendObserverNotification(); 1.450 + } 1.451 + } 1.452 + 1.453 + void Disarm() { 1.454 + mPrecompiler = nullptr; 1.455 + } 1.456 + 1.457 +private: 1.458 + ScriptPrecompiler* mPrecompiler; 1.459 +}; 1.460 + 1.461 +NS_IMETHODIMP 1.462 +NotifyPrecompilationCompleteRunnable::Run(void) 1.463 +{ 1.464 + MOZ_ASSERT(NS_IsMainThread()); 1.465 + MOZ_ASSERT(mPrecompiler); 1.466 + 1.467 + AutoSendObserverNotification notifier(mPrecompiler); 1.468 + 1.469 + if (mToken) { 1.470 + JSRuntime *rt = XPCJSRuntime::Get()->Runtime(); 1.471 + NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE); 1.472 + JS::FinishOffThreadScript(nullptr, rt, mToken); 1.473 + } 1.474 + 1.475 + return NS_OK; 1.476 +} 1.477 + 1.478 +NS_IMETHODIMP 1.479 +ScriptPrecompiler::OnStreamComplete(nsIStreamLoader* aLoader, 1.480 + nsISupports* aContext, 1.481 + nsresult aStatus, 1.482 + uint32_t aLength, 1.483 + const uint8_t* aString) 1.484 +{ 1.485 + AutoSendObserverNotification notifier(this); 1.486 + 1.487 + // Just notify that we are done with this load. 1.488 + NS_ENSURE_SUCCESS(aStatus, NS_OK); 1.489 + 1.490 + // Convert data to jschar* and prepare to call CompileOffThread. 1.491 + nsAutoString hintCharset; 1.492 + nsresult rv = 1.493 + nsScriptLoader::ConvertToUTF16(mChannel, aString, aLength, 1.494 + hintCharset, nullptr, 1.495 + mScriptBuf, mScriptLength); 1.496 + 1.497 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.498 + 1.499 + // Our goal is to cache persistently the compiled script and to avoid quota 1.500 + // checks. Since the caching mechanism decide the persistence type based on 1.501 + // the principal, we create a new global with the app's principal. 1.502 + // We then enter its compartment to compile with its principal. 1.503 + AutoSafeJSContext cx; 1.504 + RootedValue v(cx); 1.505 + SandboxOptions sandboxOptions; 1.506 + sandboxOptions.sandboxName.AssignASCII("asm.js precompilation"); 1.507 + sandboxOptions.invisibleToDebugger = true; 1.508 + sandboxOptions.discardSource = true; 1.509 + rv = CreateSandboxObject(cx, &v, mPrincipal, sandboxOptions); 1.510 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.511 + 1.512 + JSAutoCompartment ac(cx, js::UncheckedUnwrap(&v.toObject())); 1.513 + 1.514 + JS::CompileOptions options(cx, JSVERSION_DEFAULT); 1.515 + options.forceAsync = true; 1.516 + options.compileAndGo = true; 1.517 + options.installedFile = true; 1.518 + 1.519 + nsCOMPtr<nsIURI> uri; 1.520 + mChannel->GetURI(getter_AddRefs(uri)); 1.521 + nsAutoCString spec; 1.522 + uri->GetSpec(spec); 1.523 + options.setFile(spec.get()); 1.524 + 1.525 + if (!JS::CanCompileOffThread(cx, options, mScriptLength)) { 1.526 + NS_WARNING("Can't compile script off thread!"); 1.527 + return NS_OK; 1.528 + } 1.529 + 1.530 + nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable = 1.531 + new NotifyPrecompilationCompleteRunnable(this); 1.532 + 1.533 + if (!JS::CompileOffThread(cx, options, 1.534 + mScriptBuf, mScriptLength, 1.535 + OffThreadCallback, 1.536 + static_cast<void*>(runnable))) { 1.537 + NS_WARNING("Failed to compile script off thread!"); 1.538 + return NS_OK; 1.539 + } 1.540 + 1.541 + unused << runnable.forget(); 1.542 + notifier.Disarm(); 1.543 + 1.544 + return NS_OK; 1.545 +} 1.546 + 1.547 +/* static */ 1.548 +void 1.549 +ScriptPrecompiler::OffThreadCallback(void* aToken, void* aData) 1.550 +{ 1.551 + nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable = 1.552 + dont_AddRef(static_cast<NotifyPrecompilationCompleteRunnable*>(aData)); 1.553 + runnable->SetToken(aToken); 1.554 + 1.555 + NS_DispatchToMainThread(runnable); 1.556 +} 1.557 + 1.558 +void 1.559 +ScriptPrecompiler::SendObserverNotification() 1.560 +{ 1.561 + MOZ_ASSERT(mChannel && mObserver); 1.562 + MOZ_ASSERT(NS_IsMainThread()); 1.563 + 1.564 + nsCOMPtr<nsIURI> uri; 1.565 + mChannel->GetURI(getter_AddRefs(uri)); 1.566 + mObserver->Observe(uri, "script-precompiled", nullptr); 1.567 +} 1.568 + 1.569 +NS_IMETHODIMP 1.570 +mozJSSubScriptLoader::PrecompileScript(nsIURI* aURI, 1.571 + nsIPrincipal* aPrincipal, 1.572 + nsIObserver *aObserver) 1.573 +{ 1.574 + nsCOMPtr<nsIChannel> channel; 1.575 + nsresult rv = NS_NewChannel(getter_AddRefs(channel), 1.576 + aURI, nullptr, nullptr, nullptr, 1.577 + nsIRequest::LOAD_NORMAL, nullptr); 1.578 + NS_ENSURE_SUCCESS(rv, rv); 1.579 + 1.580 + nsRefPtr<ScriptPrecompiler> loadObserver = 1.581 + new ScriptPrecompiler(aObserver, aPrincipal, channel); 1.582 + 1.583 + nsCOMPtr<nsIStreamLoader> loader; 1.584 + rv = NS_NewStreamLoader(getter_AddRefs(loader), loadObserver); 1.585 + NS_ENSURE_SUCCESS(rv, rv); 1.586 + 1.587 + nsCOMPtr<nsIStreamListener> listener = loader.get(); 1.588 + rv = channel->AsyncOpen(listener, nullptr); 1.589 + NS_ENSURE_SUCCESS(rv, rv); 1.590 + 1.591 + return NS_OK; 1.592 +}