|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "mozJSSubScriptLoader.h" |
|
8 #include "mozJSComponentLoader.h" |
|
9 #include "mozJSLoaderUtils.h" |
|
10 |
|
11 #include "nsIURI.h" |
|
12 #include "nsIIOService.h" |
|
13 #include "nsIChannel.h" |
|
14 #include "nsIInputStream.h" |
|
15 #include "nsNetCID.h" |
|
16 #include "nsNetUtil.h" |
|
17 #include "nsIFileURL.h" |
|
18 #include "nsScriptLoader.h" |
|
19 #include "nsIScriptSecurityManager.h" |
|
20 #include "nsThreadUtils.h" |
|
21 |
|
22 #include "jsapi.h" |
|
23 #include "jsfriendapi.h" |
|
24 #include "js/OldDebugAPI.h" |
|
25 #include "nsJSPrincipals.h" |
|
26 #include "xpcpublic.h" // For xpc::SystemErrorReporter |
|
27 #include "xpcprivate.h" // For xpc::OptionsBase |
|
28 #include "jswrapper.h" |
|
29 |
|
30 #include "mozilla/scache/StartupCache.h" |
|
31 #include "mozilla/scache/StartupCacheUtils.h" |
|
32 #include "mozilla/unused.h" |
|
33 |
|
34 using namespace mozilla::scache; |
|
35 using namespace JS; |
|
36 using namespace xpc; |
|
37 using namespace mozilla; |
|
38 |
|
39 class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase { |
|
40 public: |
|
41 LoadSubScriptOptions(JSContext *cx = xpc_GetSafeJSContext(), |
|
42 JSObject *options = nullptr) |
|
43 : OptionsBase(cx, options) |
|
44 , target(cx) |
|
45 , charset(NullString()) |
|
46 , ignoreCache(false) |
|
47 { } |
|
48 |
|
49 virtual bool Parse() { |
|
50 return ParseObject("target", &target) && |
|
51 ParseString("charset", charset) && |
|
52 ParseBoolean("ignoreCache", &ignoreCache); |
|
53 } |
|
54 |
|
55 RootedObject target; |
|
56 nsString charset; |
|
57 bool ignoreCache; |
|
58 }; |
|
59 |
|
60 |
|
61 /* load() error msgs, XXX localize? */ |
|
62 #define LOAD_ERROR_NOSERVICE "Error creating IO Service." |
|
63 #define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)" |
|
64 #define LOAD_ERROR_NOSCHEME "Failed to get URI scheme. This is bad." |
|
65 #define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI." |
|
66 #define LOAD_ERROR_NOSTREAM "Error opening input stream (invalid filename?)" |
|
67 #define LOAD_ERROR_NOCONTENT "ContentLength not available (not a local URL?)" |
|
68 #define LOAD_ERROR_BADCHARSET "Error converting to specified charset" |
|
69 #define LOAD_ERROR_BADREAD "File Read Error." |
|
70 #define LOAD_ERROR_READUNDERFLOW "File Read Error (underflow.)" |
|
71 #define LOAD_ERROR_NOPRINCIPALS "Failed to get principals." |
|
72 #define LOAD_ERROR_NOSPEC "Failed to get URI spec. This is bad." |
|
73 #define LOAD_ERROR_CONTENTTOOBIG "ContentLength is too large" |
|
74 |
|
75 mozJSSubScriptLoader::mozJSSubScriptLoader() : mSystemPrincipal(nullptr) |
|
76 { |
|
77 // Force construction of the JS component loader. We may need it later. |
|
78 nsCOMPtr<xpcIJSModuleLoader> componentLoader = |
|
79 do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); |
|
80 } |
|
81 |
|
82 mozJSSubScriptLoader::~mozJSSubScriptLoader() |
|
83 { |
|
84 /* empty */ |
|
85 } |
|
86 |
|
87 NS_IMPL_ISUPPORTS(mozJSSubScriptLoader, mozIJSSubScriptLoader) |
|
88 |
|
89 static nsresult |
|
90 ReportError(JSContext *cx, const char *msg) |
|
91 { |
|
92 RootedValue exn(cx, JS::StringValue(JS_NewStringCopyZ(cx, msg))); |
|
93 JS_SetPendingException(cx, exn); |
|
94 return NS_OK; |
|
95 } |
|
96 |
|
97 nsresult |
|
98 mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObjArg, |
|
99 const nsAString &charset, const char *uriStr, |
|
100 nsIIOService *serv, nsIPrincipal *principal, |
|
101 bool reuseGlobal, JS::MutableHandleScript script, |
|
102 JS::MutableHandleFunction function) |
|
103 { |
|
104 RootedObject target_obj(cx, targetObjArg); |
|
105 |
|
106 script.set(nullptr); |
|
107 function.set(nullptr); |
|
108 |
|
109 // Instead of calling NS_OpenURI, we create the channel ourselves and call |
|
110 // SetContentType, to avoid expensive MIME type lookups (bug 632490). |
|
111 nsCOMPtr<nsIChannel> chan; |
|
112 nsCOMPtr<nsIInputStream> instream; |
|
113 nsresult rv = NS_NewChannel(getter_AddRefs(chan), uri, serv, |
|
114 nullptr, nullptr, nsIRequest::LOAD_NORMAL); |
|
115 if (NS_SUCCEEDED(rv)) { |
|
116 chan->SetContentType(NS_LITERAL_CSTRING("application/javascript")); |
|
117 rv = chan->Open(getter_AddRefs(instream)); |
|
118 } |
|
119 |
|
120 if (NS_FAILED(rv)) { |
|
121 return ReportError(cx, LOAD_ERROR_NOSTREAM); |
|
122 } |
|
123 |
|
124 int64_t len = -1; |
|
125 |
|
126 rv = chan->GetContentLength(&len); |
|
127 if (NS_FAILED(rv) || len == -1) { |
|
128 return ReportError(cx, LOAD_ERROR_NOCONTENT); |
|
129 } |
|
130 |
|
131 if (len > INT32_MAX) { |
|
132 return ReportError(cx, LOAD_ERROR_CONTENTTOOBIG); |
|
133 } |
|
134 |
|
135 nsCString buf; |
|
136 rv = NS_ReadInputStreamToString(instream, buf, len); |
|
137 if (NS_FAILED(rv)) |
|
138 return rv; |
|
139 |
|
140 /* set our own error reporter so we can report any bad things as catchable |
|
141 * exceptions, including the source/line number */ |
|
142 JSErrorReporter er = JS_SetErrorReporter(cx, xpc::SystemErrorReporter); |
|
143 |
|
144 JS::CompileOptions options(cx); |
|
145 options.setFileAndLine(uriStr, 1); |
|
146 if (!charset.IsVoid()) { |
|
147 jschar *scriptBuf = nullptr; |
|
148 size_t scriptLength = 0; |
|
149 |
|
150 rv = nsScriptLoader::ConvertToUTF16(nullptr, reinterpret_cast<const uint8_t*>(buf.get()), len, |
|
151 charset, nullptr, scriptBuf, scriptLength); |
|
152 |
|
153 JS::SourceBufferHolder srcBuf(scriptBuf, scriptLength, |
|
154 JS::SourceBufferHolder::GiveOwnership); |
|
155 |
|
156 if (NS_FAILED(rv)) { |
|
157 return ReportError(cx, LOAD_ERROR_BADCHARSET); |
|
158 } |
|
159 |
|
160 if (!reuseGlobal) { |
|
161 JS::Compile(cx, target_obj, options, srcBuf, script); |
|
162 } else { |
|
163 JS::CompileFunction(cx, target_obj, options, |
|
164 nullptr, 0, nullptr, |
|
165 srcBuf, |
|
166 function); |
|
167 } |
|
168 } else { |
|
169 // We only use lazy source when no special encoding is specified because |
|
170 // the lazy source loader doesn't know the encoding. |
|
171 if (!reuseGlobal) { |
|
172 options.setSourceIsLazy(true); |
|
173 script.set(JS::Compile(cx, target_obj, options, buf.get(), len)); |
|
174 } else { |
|
175 function.set(JS::CompileFunction(cx, target_obj, options, |
|
176 nullptr, 0, nullptr, buf.get(), |
|
177 len)); |
|
178 } |
|
179 } |
|
180 |
|
181 /* repent for our evil deeds */ |
|
182 JS_SetErrorReporter(cx, er); |
|
183 |
|
184 return NS_OK; |
|
185 } |
|
186 |
|
187 NS_IMETHODIMP |
|
188 mozJSSubScriptLoader::LoadSubScript(const nsAString &url, |
|
189 HandleValue target, |
|
190 const nsAString &charset, |
|
191 JSContext *cx, |
|
192 MutableHandleValue retval) |
|
193 { |
|
194 /* |
|
195 * Loads a local url and evals it into the current cx |
|
196 * Synchronous (an async version would be cool too.) |
|
197 * url: The url to load. Must be local so that it can be loaded |
|
198 * synchronously. |
|
199 * target_obj: Optional object to eval the script onto (defaults to context |
|
200 * global) |
|
201 * charset: Optional character set to use for reading |
|
202 * returns: Whatever jsval the script pointed to by the url returns. |
|
203 * Should ONLY (O N L Y !) be called from JavaScript code. |
|
204 */ |
|
205 LoadSubScriptOptions options(cx); |
|
206 options.charset = charset; |
|
207 options.target = target.isObject() ? &target.toObject() : nullptr; |
|
208 return DoLoadSubScriptWithOptions(url, options, cx, retval); |
|
209 } |
|
210 |
|
211 |
|
212 NS_IMETHODIMP |
|
213 mozJSSubScriptLoader::LoadSubScriptWithOptions(const nsAString &url, |
|
214 HandleValue optionsVal, |
|
215 JSContext *cx, |
|
216 MutableHandleValue retval) |
|
217 { |
|
218 if (!optionsVal.isObject()) |
|
219 return NS_ERROR_INVALID_ARG; |
|
220 LoadSubScriptOptions options(cx, &optionsVal.toObject()); |
|
221 if (!options.Parse()) |
|
222 return NS_ERROR_INVALID_ARG; |
|
223 return DoLoadSubScriptWithOptions(url, options, cx, retval); |
|
224 } |
|
225 |
|
226 nsresult |
|
227 mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url, |
|
228 LoadSubScriptOptions &options, |
|
229 JSContext *cx, |
|
230 MutableHandleValue retval) |
|
231 { |
|
232 nsresult rv = NS_OK; |
|
233 |
|
234 /* set the system principal if it's not here already */ |
|
235 if (!mSystemPrincipal) { |
|
236 nsCOMPtr<nsIScriptSecurityManager> secman = |
|
237 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
238 if (!secman) |
|
239 return NS_OK; |
|
240 |
|
241 rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal)); |
|
242 if (NS_FAILED(rv) || !mSystemPrincipal) |
|
243 return rv; |
|
244 } |
|
245 |
|
246 RootedObject targetObj(cx); |
|
247 mozJSComponentLoader *loader = mozJSComponentLoader::Get(); |
|
248 rv = loader->FindTargetObject(cx, &targetObj); |
|
249 NS_ENSURE_SUCCESS(rv, rv); |
|
250 |
|
251 // We base reusingGlobal off of what the loader told us, but we may not |
|
252 // actually be using that object. |
|
253 bool reusingGlobal = !JS_IsGlobalObject(targetObj); |
|
254 |
|
255 if (options.target) |
|
256 targetObj = options.target; |
|
257 |
|
258 // Remember an object out of the calling compartment so that we |
|
259 // can properly wrap the result later. |
|
260 nsCOMPtr<nsIPrincipal> principal = mSystemPrincipal; |
|
261 RootedObject result_obj(cx, targetObj); |
|
262 targetObj = JS_FindCompilationScope(cx, targetObj); |
|
263 if (!targetObj) |
|
264 return NS_ERROR_FAILURE; |
|
265 |
|
266 if (targetObj != result_obj) |
|
267 principal = GetObjectPrincipal(targetObj); |
|
268 |
|
269 JSAutoCompartment ac(cx, targetObj); |
|
270 |
|
271 /* load up the url. From here on, failures are reflected as ``custom'' |
|
272 * js exceptions */ |
|
273 nsCOMPtr<nsIURI> uri; |
|
274 nsAutoCString uriStr; |
|
275 nsAutoCString scheme; |
|
276 |
|
277 // Figure out who's calling us |
|
278 JS::AutoFilename filename; |
|
279 if (!JS::DescribeScriptedCaller(cx, &filename)) { |
|
280 // No scripted frame means we don't know who's calling, bail. |
|
281 return NS_ERROR_FAILURE; |
|
282 } |
|
283 |
|
284 // Suppress caching if we're compiling as content. |
|
285 StartupCache* cache = (principal == mSystemPrincipal) |
|
286 ? StartupCache::GetSingleton() |
|
287 : nullptr; |
|
288 nsCOMPtr<nsIIOService> serv = do_GetService(NS_IOSERVICE_CONTRACTID); |
|
289 if (!serv) { |
|
290 return ReportError(cx, LOAD_ERROR_NOSERVICE); |
|
291 } |
|
292 |
|
293 // Make sure to explicitly create the URI, since we'll need the |
|
294 // canonicalized spec. |
|
295 rv = NS_NewURI(getter_AddRefs(uri), NS_LossyConvertUTF16toASCII(url).get(), nullptr, serv); |
|
296 if (NS_FAILED(rv)) { |
|
297 return ReportError(cx, LOAD_ERROR_NOURI); |
|
298 } |
|
299 |
|
300 rv = uri->GetSpec(uriStr); |
|
301 if (NS_FAILED(rv)) { |
|
302 return ReportError(cx, LOAD_ERROR_NOSPEC); |
|
303 } |
|
304 |
|
305 rv = uri->GetScheme(scheme); |
|
306 if (NS_FAILED(rv)) { |
|
307 return ReportError(cx, LOAD_ERROR_NOSCHEME); |
|
308 } |
|
309 |
|
310 if (!scheme.EqualsLiteral("chrome")) { |
|
311 // This might be a URI to a local file, though! |
|
312 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri); |
|
313 nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(innerURI); |
|
314 if (!fileURL) { |
|
315 return ReportError(cx, LOAD_ERROR_URI_NOT_LOCAL); |
|
316 } |
|
317 |
|
318 // For file URIs prepend the filename with the filename of the |
|
319 // calling script, and " -> ". See bug 418356. |
|
320 nsAutoCString tmp(filename.get()); |
|
321 tmp.AppendLiteral(" -> "); |
|
322 tmp.Append(uriStr); |
|
323 |
|
324 uriStr = tmp; |
|
325 } |
|
326 |
|
327 bool writeScript = false; |
|
328 JSVersion version = JS_GetVersion(cx); |
|
329 nsAutoCString cachePath; |
|
330 cachePath.AppendPrintf("jssubloader/%d", version); |
|
331 PathifyURI(uri, cachePath); |
|
332 |
|
333 RootedFunction function(cx); |
|
334 RootedScript script(cx); |
|
335 if (cache && !options.ignoreCache) |
|
336 rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script); |
|
337 if (!script) { |
|
338 rv = ReadScript(uri, cx, targetObj, options.charset, |
|
339 static_cast<const char*>(uriStr.get()), serv, |
|
340 principal, reusingGlobal, &script, &function); |
|
341 writeScript = !!script; |
|
342 } |
|
343 |
|
344 if (NS_FAILED(rv) || (!script && !function)) |
|
345 return rv; |
|
346 |
|
347 if (function) { |
|
348 script = JS_GetFunctionScript(cx, function); |
|
349 } |
|
350 |
|
351 loader->NoteSubScript(script, targetObj); |
|
352 |
|
353 |
|
354 bool ok = false; |
|
355 if (function) { |
|
356 ok = JS_CallFunction(cx, targetObj, function, JS::HandleValueArray::empty(), |
|
357 retval); |
|
358 } else { |
|
359 ok = JS_ExecuteScriptVersion(cx, targetObj, script, retval, version); |
|
360 } |
|
361 |
|
362 if (ok) { |
|
363 JSAutoCompartment rac(cx, result_obj); |
|
364 if (!JS_WrapValue(cx, retval)) |
|
365 return NS_ERROR_UNEXPECTED; |
|
366 } |
|
367 |
|
368 if (cache && ok && writeScript) { |
|
369 WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script); |
|
370 } |
|
371 |
|
372 return NS_OK; |
|
373 } |
|
374 |
|
375 /** |
|
376 * Let us compile scripts from a URI off the main thread. |
|
377 */ |
|
378 |
|
379 class ScriptPrecompiler : public nsIStreamLoaderObserver |
|
380 { |
|
381 public: |
|
382 NS_DECL_ISUPPORTS |
|
383 NS_DECL_NSISTREAMLOADEROBSERVER |
|
384 |
|
385 ScriptPrecompiler(nsIObserver* aObserver, |
|
386 nsIPrincipal* aPrincipal, |
|
387 nsIChannel* aChannel) |
|
388 : mObserver(aObserver) |
|
389 , mPrincipal(aPrincipal) |
|
390 , mChannel(aChannel) |
|
391 , mScriptBuf(nullptr) |
|
392 , mScriptLength(0) |
|
393 {} |
|
394 |
|
395 virtual ~ScriptPrecompiler() |
|
396 { |
|
397 if (mScriptBuf) { |
|
398 js_free(mScriptBuf); |
|
399 } |
|
400 } |
|
401 |
|
402 static void OffThreadCallback(void *aToken, void *aData); |
|
403 |
|
404 /* Sends the "done" notification back. Main thread only. */ |
|
405 void SendObserverNotification(); |
|
406 |
|
407 private: |
|
408 nsRefPtr<nsIObserver> mObserver; |
|
409 nsRefPtr<nsIPrincipal> mPrincipal; |
|
410 nsRefPtr<nsIChannel> mChannel; |
|
411 jschar* mScriptBuf; |
|
412 size_t mScriptLength; |
|
413 }; |
|
414 |
|
415 NS_IMPL_ISUPPORTS(ScriptPrecompiler, nsIStreamLoaderObserver); |
|
416 |
|
417 class NotifyPrecompilationCompleteRunnable : public nsRunnable |
|
418 { |
|
419 public: |
|
420 NS_DECL_NSIRUNNABLE |
|
421 |
|
422 NotifyPrecompilationCompleteRunnable(ScriptPrecompiler* aPrecompiler) |
|
423 : mPrecompiler(aPrecompiler) |
|
424 , mToken(nullptr) |
|
425 {} |
|
426 |
|
427 void SetToken(void* aToken) { |
|
428 MOZ_ASSERT(aToken && !mToken); |
|
429 mToken = aToken; |
|
430 } |
|
431 |
|
432 protected: |
|
433 nsRefPtr<ScriptPrecompiler> mPrecompiler; |
|
434 void* mToken; |
|
435 }; |
|
436 |
|
437 /* RAII helper class to send observer notifications */ |
|
438 class AutoSendObserverNotification { |
|
439 public: |
|
440 AutoSendObserverNotification(ScriptPrecompiler* aPrecompiler) |
|
441 : mPrecompiler(aPrecompiler) |
|
442 {} |
|
443 |
|
444 ~AutoSendObserverNotification() { |
|
445 if (mPrecompiler) { |
|
446 mPrecompiler->SendObserverNotification(); |
|
447 } |
|
448 } |
|
449 |
|
450 void Disarm() { |
|
451 mPrecompiler = nullptr; |
|
452 } |
|
453 |
|
454 private: |
|
455 ScriptPrecompiler* mPrecompiler; |
|
456 }; |
|
457 |
|
458 NS_IMETHODIMP |
|
459 NotifyPrecompilationCompleteRunnable::Run(void) |
|
460 { |
|
461 MOZ_ASSERT(NS_IsMainThread()); |
|
462 MOZ_ASSERT(mPrecompiler); |
|
463 |
|
464 AutoSendObserverNotification notifier(mPrecompiler); |
|
465 |
|
466 if (mToken) { |
|
467 JSRuntime *rt = XPCJSRuntime::Get()->Runtime(); |
|
468 NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE); |
|
469 JS::FinishOffThreadScript(nullptr, rt, mToken); |
|
470 } |
|
471 |
|
472 return NS_OK; |
|
473 } |
|
474 |
|
475 NS_IMETHODIMP |
|
476 ScriptPrecompiler::OnStreamComplete(nsIStreamLoader* aLoader, |
|
477 nsISupports* aContext, |
|
478 nsresult aStatus, |
|
479 uint32_t aLength, |
|
480 const uint8_t* aString) |
|
481 { |
|
482 AutoSendObserverNotification notifier(this); |
|
483 |
|
484 // Just notify that we are done with this load. |
|
485 NS_ENSURE_SUCCESS(aStatus, NS_OK); |
|
486 |
|
487 // Convert data to jschar* and prepare to call CompileOffThread. |
|
488 nsAutoString hintCharset; |
|
489 nsresult rv = |
|
490 nsScriptLoader::ConvertToUTF16(mChannel, aString, aLength, |
|
491 hintCharset, nullptr, |
|
492 mScriptBuf, mScriptLength); |
|
493 |
|
494 NS_ENSURE_SUCCESS(rv, NS_OK); |
|
495 |
|
496 // Our goal is to cache persistently the compiled script and to avoid quota |
|
497 // checks. Since the caching mechanism decide the persistence type based on |
|
498 // the principal, we create a new global with the app's principal. |
|
499 // We then enter its compartment to compile with its principal. |
|
500 AutoSafeJSContext cx; |
|
501 RootedValue v(cx); |
|
502 SandboxOptions sandboxOptions; |
|
503 sandboxOptions.sandboxName.AssignASCII("asm.js precompilation"); |
|
504 sandboxOptions.invisibleToDebugger = true; |
|
505 sandboxOptions.discardSource = true; |
|
506 rv = CreateSandboxObject(cx, &v, mPrincipal, sandboxOptions); |
|
507 NS_ENSURE_SUCCESS(rv, NS_OK); |
|
508 |
|
509 JSAutoCompartment ac(cx, js::UncheckedUnwrap(&v.toObject())); |
|
510 |
|
511 JS::CompileOptions options(cx, JSVERSION_DEFAULT); |
|
512 options.forceAsync = true; |
|
513 options.compileAndGo = true; |
|
514 options.installedFile = true; |
|
515 |
|
516 nsCOMPtr<nsIURI> uri; |
|
517 mChannel->GetURI(getter_AddRefs(uri)); |
|
518 nsAutoCString spec; |
|
519 uri->GetSpec(spec); |
|
520 options.setFile(spec.get()); |
|
521 |
|
522 if (!JS::CanCompileOffThread(cx, options, mScriptLength)) { |
|
523 NS_WARNING("Can't compile script off thread!"); |
|
524 return NS_OK; |
|
525 } |
|
526 |
|
527 nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable = |
|
528 new NotifyPrecompilationCompleteRunnable(this); |
|
529 |
|
530 if (!JS::CompileOffThread(cx, options, |
|
531 mScriptBuf, mScriptLength, |
|
532 OffThreadCallback, |
|
533 static_cast<void*>(runnable))) { |
|
534 NS_WARNING("Failed to compile script off thread!"); |
|
535 return NS_OK; |
|
536 } |
|
537 |
|
538 unused << runnable.forget(); |
|
539 notifier.Disarm(); |
|
540 |
|
541 return NS_OK; |
|
542 } |
|
543 |
|
544 /* static */ |
|
545 void |
|
546 ScriptPrecompiler::OffThreadCallback(void* aToken, void* aData) |
|
547 { |
|
548 nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable = |
|
549 dont_AddRef(static_cast<NotifyPrecompilationCompleteRunnable*>(aData)); |
|
550 runnable->SetToken(aToken); |
|
551 |
|
552 NS_DispatchToMainThread(runnable); |
|
553 } |
|
554 |
|
555 void |
|
556 ScriptPrecompiler::SendObserverNotification() |
|
557 { |
|
558 MOZ_ASSERT(mChannel && mObserver); |
|
559 MOZ_ASSERT(NS_IsMainThread()); |
|
560 |
|
561 nsCOMPtr<nsIURI> uri; |
|
562 mChannel->GetURI(getter_AddRefs(uri)); |
|
563 mObserver->Observe(uri, "script-precompiled", nullptr); |
|
564 } |
|
565 |
|
566 NS_IMETHODIMP |
|
567 mozJSSubScriptLoader::PrecompileScript(nsIURI* aURI, |
|
568 nsIPrincipal* aPrincipal, |
|
569 nsIObserver *aObserver) |
|
570 { |
|
571 nsCOMPtr<nsIChannel> channel; |
|
572 nsresult rv = NS_NewChannel(getter_AddRefs(channel), |
|
573 aURI, nullptr, nullptr, nullptr, |
|
574 nsIRequest::LOAD_NORMAL, nullptr); |
|
575 NS_ENSURE_SUCCESS(rv, rv); |
|
576 |
|
577 nsRefPtr<ScriptPrecompiler> loadObserver = |
|
578 new ScriptPrecompiler(aObserver, aPrincipal, channel); |
|
579 |
|
580 nsCOMPtr<nsIStreamLoader> loader; |
|
581 rv = NS_NewStreamLoader(getter_AddRefs(loader), loadObserver); |
|
582 NS_ENSURE_SUCCESS(rv, rv); |
|
583 |
|
584 nsCOMPtr<nsIStreamListener> listener = loader.get(); |
|
585 rv = channel->AsyncOpen(listener, nullptr); |
|
586 NS_ENSURE_SUCCESS(rv, rv); |
|
587 |
|
588 return NS_OK; |
|
589 } |