1 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1999
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributors:
25 : * Mike Shaver <shaver@zeroknowledge.com>
26 : * John Bandhauer <jband@netscape.com>
27 : * IBM Corp.
28 : * Robert Ginda <rginda@netscape.com>
29 : *
30 : * Alternatively, the contents of this file may be used under the terms of
31 : * either of the GNU General Public License Version 2 or later (the "GPL"),
32 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 : * in which case the provisions of the GPL or the LGPL are applicable instead
34 : * of those above. If you wish to allow use of your version of this file only
35 : * under the terms of either the GPL or the LGPL, and not to allow others to
36 : * use your version of this file under the terms of the MPL, indicate your
37 : * decision by deleting the provisions above and replace them with the notice
38 : * and other provisions required by the GPL or the LGPL. If you do not delete
39 : * the provisions above, a recipient may use your version of this file under
40 : * the terms of any one of the MPL, the GPL or the LGPL.
41 : *
42 : * ***** END LICENSE BLOCK ***** */
43 :
44 : #include "mozilla/Attributes.h"
45 :
46 : #ifdef MOZ_LOGGING
47 : #define FORCE_PR_LOG
48 : #endif
49 :
50 : #include <stdarg.h>
51 :
52 : #include "prlog.h"
53 : #ifdef ANDROID
54 : #include <android/log.h>
55 : #endif
56 :
57 : #include "nsCOMPtr.h"
58 : #include "nsAutoPtr.h"
59 : #include "nsICategoryManager.h"
60 : #include "nsIComponentManager.h"
61 : #include "mozilla/Module.h"
62 : #include "nsILocalFile.h"
63 : #include "nsIServiceManager.h"
64 : #include "nsISupports.h"
65 : #include "mozJSComponentLoader.h"
66 : #include "mozJSLoaderUtils.h"
67 : #include "nsIJSRuntimeService.h"
68 : #include "nsIJSContextStack.h"
69 : #include "nsIXPConnect.h"
70 : #include "nsCRT.h"
71 : #include "nsMemory.h"
72 : #include "nsIObserverService.h"
73 : #include "nsIXPCScriptable.h"
74 : #include "nsString.h"
75 : #include "nsIScriptSecurityManager.h"
76 : #include "nsIURI.h"
77 : #include "nsIFileURL.h"
78 : #include "nsIJARURI.h"
79 : #include "nsNetUtil.h"
80 : #include "nsDOMFile.h"
81 : #include "jsxdrapi.h"
82 : #include "jsprf.h"
83 : #include "nsJSPrincipals.h"
84 : // For reporting errors with the console service
85 : #include "nsIScriptError.h"
86 : #include "nsIConsoleService.h"
87 : #include "nsIStorageStream.h"
88 : #include "nsIStringStream.h"
89 : #include "prmem.h"
90 : #if defined(XP_WIN)
91 : #include "nsILocalFileWin.h"
92 : #endif
93 : #include "xpcprivate.h"
94 : #include "xpcpublic.h"
95 : #include "nsIResProtocolHandler.h"
96 :
97 : #include "mozilla/scache/StartupCache.h"
98 : #include "mozilla/scache/StartupCacheUtils.h"
99 : #include "mozilla/Omnijar.h"
100 :
101 : #include "jsdbgapi.h"
102 :
103 : #include "mozilla/FunctionTimer.h"
104 :
105 : using namespace mozilla;
106 : using namespace mozilla::scache;
107 :
108 : static const char kJSRuntimeServiceContractID[] = "@mozilla.org/js/xpc/RuntimeService;1";
109 : static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1";
110 : static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
111 : static const char kJSCachePrefix[] = "jsloader";
112 :
113 : /* Some platforms don't have an implementation of PR_MemMap(). */
114 : #ifndef XP_OS2
115 : #define HAVE_PR_MEMMAP
116 : #endif
117 :
118 : /**
119 : * Buffer sizes for serialization and deserialization of scripts.
120 : * FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008
121 : */
122 : #define XPC_SERIALIZATION_BUFFER_SIZE (64 * 1024)
123 : #define XPC_DESERIALIZATION_BUFFER_SIZE (12 * 8192)
124 :
125 : #ifdef PR_LOGGING
126 : // NSPR_LOG_MODULES=JSComponentLoader:5
127 : static PRLogModuleInfo *gJSCLLog;
128 : #endif
129 :
130 : #define LOG(args) PR_LOG(gJSCLLog, PR_LOG_DEBUG, args)
131 :
132 : // Components.utils.import error messages
133 : #define ERROR_SCOPE_OBJ "%s - Second argument must be an object."
134 : #define ERROR_NOT_PRESENT "%s - EXPORTED_SYMBOLS is not present."
135 : #define ERROR_NOT_AN_ARRAY "%s - EXPORTED_SYMBOLS is not an array."
136 : #define ERROR_GETTING_ARRAY_LENGTH "%s - Error getting array length of EXPORTED_SYMBOLS."
137 : #define ERROR_ARRAY_ELEMENT "%s - EXPORTED_SYMBOLS[%d] is not a string."
138 : #define ERROR_GETTING_SYMBOL "%s - Could not get symbol '%s'."
139 : #define ERROR_SETTING_SYMBOL "%s - Could not set symbol '%s' on target object."
140 :
141 : void
142 90 : mozJSLoaderErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep)
143 : {
144 : nsresult rv;
145 :
146 : /* Use the console service to register the error. */
147 : nsCOMPtr<nsIConsoleService> consoleService =
148 180 : do_GetService(NS_CONSOLESERVICE_CONTRACTID);
149 :
150 : /*
151 : * Make an nsIScriptError, populate it with information from this
152 : * error, then log it with the console service. The UI can then
153 : * poll the service to update the Error console.
154 : */
155 : nsCOMPtr<nsIScriptError> errorObject =
156 180 : do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
157 :
158 90 : if (consoleService && errorObject) {
159 : /*
160 : * Got an error object; prepare appropriate-width versions of
161 : * various arguments to it.
162 : */
163 180 : nsAutoString fileUni;
164 90 : fileUni.AssignWithConversion(rep->filename);
165 :
166 90 : PRUint32 column = rep->uctokenptr - rep->uclinebuf;
167 :
168 90 : rv = errorObject->Init(reinterpret_cast<const PRUnichar*>
169 : (rep->ucmessage),
170 : fileUni.get(),
171 : reinterpret_cast<const PRUnichar*>
172 : (rep->uclinebuf),
173 : rep->lineno, column, rep->flags,
174 90 : "component javascript");
175 90 : if (NS_SUCCEEDED(rv)) {
176 90 : rv = consoleService->LogMessage(errorObject);
177 90 : if (NS_SUCCEEDED(rv)) {
178 : // We're done! Skip return to fall thru to stderr
179 : // printout, for the benefit of those invoking the
180 : // browser with -console
181 : // return;
182 : }
183 : }
184 : }
185 :
186 : /*
187 : * If any of the above fails for some reason, fall back to
188 : * printing to stderr.
189 : */
190 : #ifdef DEBUG
191 : fprintf(stderr, "JS Component Loader: %s %s:%d\n"
192 : " %s\n",
193 : JSREPORT_IS_WARNING(rep->flags) ? "WARNING" : "ERROR",
194 : rep->filename, rep->lineno,
195 90 : message ? message : "<no message>");
196 : #endif
197 90 : }
198 :
199 : static JSBool
200 44283 : Dump(JSContext *cx, unsigned argc, jsval *vp)
201 : {
202 : JSString *str;
203 44283 : if (!argc)
204 0 : return true;
205 :
206 44283 : str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
207 44283 : if (!str)
208 0 : return false;
209 :
210 : size_t length;
211 44283 : const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
212 44283 : if (!chars)
213 0 : return false;
214 :
215 88566 : NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const PRUnichar*>(chars));
216 : #ifdef ANDROID
217 : __android_log_print(ANDROID_LOG_INFO, "Gecko", utf8str.get());
218 : #endif
219 44283 : fputs(utf8str.get(), stdout);
220 44283 : fflush(stdout);
221 44283 : return true;
222 : }
223 :
224 : static JSBool
225 0 : Debug(JSContext *cx, unsigned argc, jsval *vp)
226 : {
227 : #ifdef DEBUG
228 0 : return Dump(cx, argc, vp);
229 : #else
230 : return true;
231 : #endif
232 : }
233 :
234 : static JSBool
235 1070 : Atob(JSContext *cx, unsigned argc, jsval *vp)
236 : {
237 1070 : if (!argc)
238 0 : return true;
239 :
240 1070 : return xpc::Base64Decode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
241 : }
242 :
243 : static JSBool
244 6763 : Btoa(JSContext *cx, unsigned argc, jsval *vp)
245 : {
246 6763 : if (!argc)
247 0 : return true;
248 :
249 6763 : return xpc::Base64Encode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp));
250 : }
251 :
252 : static JSBool
253 11 : File(JSContext *cx, unsigned argc, jsval *vp)
254 : {
255 : nsresult rv;
256 :
257 11 : if (!argc) {
258 1 : XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx);
259 1 : return false;
260 : }
261 :
262 20 : nsCOMPtr<nsISupports> native;
263 10 : rv = nsDOMFileFile::NewFile(getter_AddRefs(native));
264 10 : if (NS_FAILED(rv)) {
265 0 : XPCThrower::Throw(rv, cx);
266 0 : return false;
267 : }
268 :
269 20 : nsCOMPtr<nsIJSNativeInitializer> initializer = do_QueryInterface(native);
270 10 : NS_ASSERTION(initializer, "what?");
271 :
272 10 : rv = initializer->Initialize(nsnull, cx, nsnull, argc, JS_ARGV(cx, vp));
273 10 : if (NS_FAILED(rv)) {
274 2 : XPCThrower::Throw(rv, cx);
275 2 : return false;
276 : }
277 :
278 8 : nsXPConnect* xpc = nsXPConnect::GetXPConnect();
279 8 : if (!xpc) {
280 0 : XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx);
281 0 : return false;
282 : }
283 :
284 8 : JSObject* glob = JS_GetGlobalForScopeChain(cx);
285 :
286 16 : nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
287 : jsval retval;
288 : rv = xpc->WrapNativeToJSVal(cx, glob, native, nsnull,
289 : &NS_GET_IID(nsISupports),
290 8 : true, &retval, nsnull);
291 8 : if (NS_FAILED(rv)) {
292 0 : XPCThrower::Throw(rv, cx);
293 0 : return false;
294 : }
295 :
296 8 : JS_SET_RVAL(cx, vp, retval);
297 8 : return true;
298 : }
299 :
300 : static JSFunctionSpec gGlobalFun[] = {
301 : {"dump", Dump, 1,0},
302 : {"debug", Debug, 1,0},
303 : {"atob", Atob, 1,0},
304 : {"btoa", Btoa, 1,0},
305 : {"File", File, 1,JSFUN_CONSTRUCTOR},
306 : {nsnull,nsnull,0,0}
307 : };
308 :
309 : class JSCLContextHelper
310 : {
311 : public:
312 : JSCLContextHelper(mozJSComponentLoader* loader);
313 : ~JSCLContextHelper();
314 :
315 : void reportErrorAfterPop(char *buf);
316 :
317 277585 : operator JSContext*() const {return mContext;}
318 :
319 : private:
320 : JSContext* mContext;
321 : nsIThreadJSContextStack* mContextStack;
322 : char* mBuf;
323 :
324 : // prevent copying and assignment
325 : JSCLContextHelper(const JSCLContextHelper &) MOZ_DELETE;
326 : const JSCLContextHelper& operator=(const JSCLContextHelper &) MOZ_DELETE;
327 : };
328 :
329 :
330 : class JSCLAutoErrorReporterSetter
331 : {
332 : public:
333 13893 : JSCLAutoErrorReporterSetter(JSContext* cx, JSErrorReporter reporter)
334 13893 : {mContext = cx; mOldReporter = JS_SetErrorReporter(cx, reporter);}
335 13893 : ~JSCLAutoErrorReporterSetter()
336 13893 : {JS_SetErrorReporter(mContext, mOldReporter);}
337 : private:
338 : JSContext* mContext;
339 : JSErrorReporter mOldReporter;
340 :
341 : JSCLAutoErrorReporterSetter(const JSCLAutoErrorReporterSetter &) MOZ_DELETE;
342 : const JSCLAutoErrorReporterSetter& operator=(const JSCLAutoErrorReporterSetter &) MOZ_DELETE;
343 : };
344 :
345 : static nsresult
346 1 : ReportOnCaller(JSContext *callerContext,
347 : const char *format, ...) {
348 1 : if (!callerContext) {
349 0 : return NS_ERROR_FAILURE;
350 : }
351 :
352 : va_list ap;
353 1 : va_start(ap, format);
354 :
355 1 : char *buf = JS_vsmprintf(format, ap);
356 1 : if (!buf) {
357 0 : return NS_ERROR_OUT_OF_MEMORY;
358 : }
359 :
360 1 : JS_ReportError(callerContext, buf);
361 1 : JS_smprintf_free(buf);
362 :
363 1 : return NS_OK;
364 : }
365 :
366 : static nsresult
367 2 : ReportOnCaller(JSCLContextHelper &helper,
368 : const char *format, ...)
369 : {
370 : va_list ap;
371 2 : va_start(ap, format);
372 :
373 2 : char *buf = JS_vsmprintf(format, ap);
374 2 : if (!buf) {
375 0 : return NS_ERROR_OUT_OF_MEMORY;
376 : }
377 :
378 2 : helper.reportErrorAfterPop(buf);
379 :
380 2 : return NS_OK;
381 : }
382 :
383 965 : mozJSComponentLoader::mozJSComponentLoader()
384 : : mRuntime(nsnull),
385 : mContext(nsnull),
386 965 : mInitialized(false)
387 : {
388 965 : NS_ASSERTION(!sSelf, "mozJSComponentLoader should be a singleton");
389 :
390 : #ifdef PR_LOGGING
391 965 : if (!gJSCLLog) {
392 965 : gJSCLLog = PR_NewLogModule("JSComponentLoader");
393 : }
394 : #endif
395 :
396 965 : sSelf = this;
397 965 : }
398 :
399 2895 : mozJSComponentLoader::~mozJSComponentLoader()
400 : {
401 965 : if (mInitialized) {
402 0 : NS_ERROR("'xpcom-shutdown-loaders' was not fired before cleaning up mozJSComponentLoader");
403 0 : UnloadModules();
404 : }
405 :
406 965 : sSelf = nsnull;
407 3860 : }
408 :
409 : mozJSComponentLoader*
410 : mozJSComponentLoader::sSelf;
411 :
412 272806 : NS_IMPL_ISUPPORTS3(mozJSComponentLoader,
413 : mozilla::ModuleLoader,
414 : xpcIJSModuleLoader,
415 : nsIObserver)
416 :
417 : nsresult
418 965 : mozJSComponentLoader::ReallyInit()
419 : {
420 : NS_TIME_FUNCTION;
421 : nsresult rv;
422 :
423 :
424 : /*
425 : * Get the JSRuntime from the runtime svc, if possible.
426 : * We keep a reference around, because it's a Bad Thing if the runtime
427 : * service gets shut down before we're done. Bad!
428 : */
429 :
430 965 : mRuntimeService = do_GetService(kJSRuntimeServiceContractID, &rv);
431 2895 : if (NS_FAILED(rv) ||
432 1930 : NS_FAILED(rv = mRuntimeService->GetRuntime(&mRuntime)))
433 0 : return rv;
434 :
435 965 : mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
436 965 : if (NS_FAILED(rv))
437 0 : return rv;
438 :
439 : // Create our compilation context.
440 965 : mContext = JS_NewContext(mRuntime, 256);
441 965 : if (!mContext)
442 0 : return NS_ERROR_OUT_OF_MEMORY;
443 :
444 965 : uint32_t options = JS_GetOptions(mContext);
445 965 : JS_SetOptions(mContext, options | JSOPTION_XML);
446 :
447 : // Always use the latest js version
448 965 : JS_SetVersion(mContext, JSVERSION_LATEST);
449 :
450 : nsCOMPtr<nsIScriptSecurityManager> secman =
451 1930 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
452 965 : if (!secman)
453 0 : return NS_ERROR_FAILURE;
454 :
455 965 : rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal));
456 965 : if (NS_FAILED(rv) || !mSystemPrincipal)
457 0 : return NS_ERROR_FAILURE;
458 :
459 965 : if (!mModules.Init(32))
460 0 : return NS_ERROR_OUT_OF_MEMORY;
461 965 : if (!mImports.Init(32))
462 0 : return NS_ERROR_OUT_OF_MEMORY;
463 965 : if (!mInProgressImports.Init(32))
464 0 : return NS_ERROR_OUT_OF_MEMORY;
465 :
466 : nsCOMPtr<nsIObserverService> obsSvc =
467 1930 : do_GetService(kObserverServiceContractID, &rv);
468 965 : NS_ENSURE_SUCCESS(rv, rv);
469 :
470 965 : rv = obsSvc->AddObserver(this, "xpcom-shutdown-loaders", false);
471 965 : NS_ENSURE_SUCCESS(rv, rv);
472 :
473 : // Set up localized comparison and string conversion
474 965 : xpc_LocalizeContext(mContext);
475 :
476 : #ifdef DEBUG_shaver_off
477 : fprintf(stderr, "mJCL: ReallyInit success!\n");
478 : #endif
479 965 : mInitialized = true;
480 :
481 965 : return NS_OK;
482 : }
483 :
484 : const mozilla::Module*
485 2063 : mozJSComponentLoader::LoadModule(FileLocation &aFile)
486 : {
487 4126 : nsCOMPtr<nsILocalFile> file = aFile.GetBaseFile();
488 :
489 4126 : nsCString spec;
490 2063 : aFile.GetURIString(spec);
491 :
492 4126 : nsCOMPtr<nsIURI> uri;
493 2063 : nsresult rv = NS_NewURI(getter_AddRefs(uri), spec);
494 2063 : if (NS_FAILED(rv))
495 0 : return NULL;
496 :
497 : #ifdef NS_FUNCTION_TIMER
498 : NS_TIME_FUNCTION_FMT("%s (line %d) (file: %s)", MOZ_FUNCTION_NAME,
499 : __LINE__, spec.get());
500 : #endif
501 :
502 2063 : if (!mInitialized) {
503 95 : rv = ReallyInit();
504 95 : if (NS_FAILED(rv))
505 0 : return NULL;
506 : }
507 :
508 : ModuleEntry* mod;
509 2063 : if (mModules.Get(spec, &mod))
510 0 : return mod;
511 :
512 4126 : nsAutoPtr<ModuleEntry> entry(new ModuleEntry);
513 2063 : if (!entry)
514 0 : return NULL;
515 :
516 2063 : rv = GlobalForLocation(file, uri, &entry->global,
517 4126 : &entry->location, nsnull);
518 2063 : if (NS_FAILED(rv)) {
519 : #ifdef DEBUG_shaver
520 : fprintf(stderr, "GlobalForLocation failed!\n");
521 : #endif
522 0 : return NULL;
523 : }
524 :
525 : nsCOMPtr<nsIXPConnect> xpc = do_GetService(kXPConnectServiceContractID,
526 4126 : &rv);
527 2063 : if (NS_FAILED(rv))
528 0 : return NULL;
529 :
530 4126 : nsCOMPtr<nsIComponentManager> cm;
531 2063 : rv = NS_GetComponentManager(getter_AddRefs(cm));
532 2063 : if (NS_FAILED(rv))
533 0 : return NULL;
534 :
535 4126 : JSCLContextHelper cx(this);
536 4126 : JSAutoEnterCompartment ac;
537 2063 : if (!ac.enter(cx, entry->global))
538 0 : return NULL;
539 :
540 : JSObject* cm_jsobj;
541 4126 : nsCOMPtr<nsIXPConnectJSObjectHolder> cm_holder;
542 4126 : rv = xpc->WrapNative(cx, entry->global, cm,
543 : NS_GET_IID(nsIComponentManager),
544 4126 : getter_AddRefs(cm_holder));
545 :
546 2063 : if (NS_FAILED(rv)) {
547 : #ifdef DEBUG_shaver
548 : fprintf(stderr, "WrapNative(%p,%p,nsIComponentManager) failed: %x\n",
549 : (void *)(JSContext*)cx, (void *)mCompMgr, rv);
550 : #endif
551 0 : return NULL;
552 : }
553 :
554 2063 : rv = cm_holder->GetJSObject(&cm_jsobj);
555 2063 : if (NS_FAILED(rv)) {
556 : #ifdef DEBUG_shaver
557 : fprintf(stderr, "GetJSObject of ComponentManager failed\n");
558 : #endif
559 0 : return NULL;
560 : }
561 :
562 : JSObject* file_jsobj;
563 4126 : nsCOMPtr<nsIXPConnectJSObjectHolder> file_holder;
564 4126 : rv = xpc->WrapNative(cx, entry->global, file,
565 : NS_GET_IID(nsIFile),
566 4126 : getter_AddRefs(file_holder));
567 :
568 2063 : if (NS_FAILED(rv)) {
569 0 : return NULL;
570 : }
571 :
572 2063 : rv = file_holder->GetJSObject(&file_jsobj);
573 2063 : if (NS_FAILED(rv)) {
574 0 : return NULL;
575 : }
576 :
577 4126 : JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);
578 :
579 : jsval NSGetFactory_val;
580 :
581 4126 : if (!JS_GetProperty(cx, entry->global, "NSGetFactory", &NSGetFactory_val) ||
582 2063 : JSVAL_IS_VOID(NSGetFactory_val)) {
583 0 : return NULL;
584 : }
585 :
586 2063 : if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
587 0 : nsCAutoString spec;
588 0 : uri->GetSpec(spec);
589 : JS_ReportError(cx, "%s has NSGetFactory property that is not a function",
590 0 : spec.get());
591 0 : return NULL;
592 : }
593 :
594 : JSObject *jsGetFactoryObj;
595 4126 : if (!JS_ValueToObject(cx, NSGetFactory_val, &jsGetFactoryObj) ||
596 2063 : !jsGetFactoryObj) {
597 : /* XXX report error properly */
598 0 : return NULL;
599 : }
600 :
601 2063 : rv = xpc->WrapJS(cx, jsGetFactoryObj,
602 2063 : NS_GET_IID(xpcIJSGetFactory), getter_AddRefs(entry->getfactoryobj));
603 2063 : if (NS_FAILED(rv)) {
604 : /* XXX report error properly */
605 : #ifdef DEBUG
606 0 : fprintf(stderr, "mJCL: couldn't get nsIModule from jsval\n");
607 : #endif
608 0 : return NULL;
609 : }
610 :
611 : // Cache this module for later
612 2063 : if (!mModules.Put(spec, entry))
613 0 : return NULL;
614 :
615 : // The hash owns the ModuleEntry now, forget about it
616 2063 : return entry.forget();
617 : }
618 :
619 : // Some stack based classes for cleaning up on early return
620 : #ifdef HAVE_PR_MEMMAP
621 : class FileAutoCloser
622 : {
623 : public:
624 11237 : explicit FileAutoCloser(PRFileDesc *file) : mFile(file) {}
625 11237 : ~FileAutoCloser() { PR_Close(mFile); }
626 : private:
627 : PRFileDesc *mFile;
628 : };
629 :
630 : class FileMapAutoCloser
631 : {
632 : public:
633 11237 : explicit FileMapAutoCloser(PRFileMap *map) : mMap(map) {}
634 11237 : ~FileMapAutoCloser() { PR_CloseFileMap(mMap); }
635 : private:
636 : PRFileMap *mMap;
637 : };
638 : #else
639 : class ANSIFileAutoCloser
640 : {
641 : public:
642 : explicit ANSIFileAutoCloser(FILE *file) : mFile(file) {}
643 : ~ANSIFileAutoCloser() { fclose(mFile); }
644 : private:
645 : FILE *mFile;
646 : };
647 : #endif
648 :
649 : nsresult
650 11830 : mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
651 : nsIURI *aURI,
652 : JSObject **aGlobal,
653 : char **aLocation,
654 : jsval *exception)
655 : {
656 : nsresult rv;
657 :
658 23660 : JSCLContextHelper cx(this);
659 :
660 11830 : JS_AbortIfWrongThread(JS_GetRuntime(cx));
661 :
662 : // preserve caller's compartment
663 23660 : js::AutoPreserveCompartment pc(cx);
664 :
665 23660 : nsCOMPtr<nsIXPCScriptable> backstagePass;
666 11830 : rv = mRuntimeService->GetBackstagePass(getter_AddRefs(backstagePass));
667 11830 : NS_ENSURE_SUCCESS(rv, rv);
668 :
669 23660 : JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);
670 :
671 : nsCOMPtr<nsIXPConnect> xpc =
672 23660 : do_GetService(kXPConnectServiceContractID, &rv);
673 11830 : NS_ENSURE_SUCCESS(rv, rv);
674 :
675 : // Make sure InitClassesWithNewWrappedGlobal() installs the
676 : // backstage pass as the global in our compilation context.
677 11830 : JS_SetGlobalObject(cx, nsnull);
678 :
679 23660 : nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
680 11830 : rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
681 : mSystemPrincipal,
682 : nsIXPConnect::
683 : FLAG_SYSTEM_GLOBAL_OBJECT,
684 11830 : getter_AddRefs(holder));
685 11830 : NS_ENSURE_SUCCESS(rv, rv);
686 :
687 : JSObject *global;
688 11830 : rv = holder->GetJSObject(&global);
689 11830 : NS_ENSURE_SUCCESS(rv, rv);
690 :
691 23660 : JSAutoEnterCompartment ac;
692 11830 : if (!ac.enter(cx, global))
693 0 : return NS_ERROR_FAILURE;
694 :
695 23660 : if (!JS_DefineFunctions(cx, global, gGlobalFun) ||
696 11830 : !JS_DefineProfilingFunctions(cx, global)) {
697 0 : return NS_ERROR_FAILURE;
698 : }
699 :
700 11830 : bool realFile = false;
701 : // need to be extra careful checking for URIs pointing to files
702 : // EnsureFile may not always get called, especially on resource URIs
703 : // so we need to call GetFile to make sure this is a valid file
704 23660 : nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
705 23660 : nsCOMPtr<nsIFile> testFile;
706 11830 : if (NS_SUCCEEDED(rv)) {
707 11728 : fileURL->GetFile(getter_AddRefs(testFile));
708 : }
709 :
710 11830 : if (testFile) {
711 11728 : realFile = true;
712 :
713 23456 : nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
714 11728 : rv = xpc->WrapNative(cx, global, aComponentFile,
715 : NS_GET_IID(nsILocalFile),
716 11728 : getter_AddRefs(locationHolder));
717 11728 : NS_ENSURE_SUCCESS(rv, rv);
718 :
719 : JSObject *locationObj;
720 11728 : rv = locationHolder->GetJSObject(&locationObj);
721 11728 : NS_ENSURE_SUCCESS(rv, rv);
722 :
723 11728 : if (!JS_DefineProperty(cx, global, "__LOCATION__",
724 11728 : OBJECT_TO_JSVAL(locationObj), nsnull, nsnull, 0))
725 0 : return NS_ERROR_FAILURE;
726 : }
727 :
728 23660 : nsCAutoString nativePath;
729 11830 : rv = aURI->GetSpec(nativePath);
730 11830 : NS_ENSURE_SUCCESS(rv, rv);
731 :
732 : // Expose the URI from which the script was imported through a special
733 : // variable that we insert into the JSM.
734 11830 : JSString *exposedUri = JS_NewStringCopyN(cx, nativePath.get(), nativePath.Length());
735 11830 : if (!JS_DefineProperty(cx, global, "__URI__",
736 11830 : STRING_TO_JSVAL(exposedUri), nsnull, nsnull, 0))
737 0 : return NS_ERROR_FAILURE;
738 :
739 :
740 11830 : JSScript *script = nsnull;
741 :
742 : // Before compiling the script, first check to see if we have it in
743 : // the startupcache. Note: as a rule, startupcache errors are not fatal
744 : // to loading the script, since we can always slow-load.
745 :
746 11830 : bool writeToCache = false;
747 11830 : StartupCache* cache = StartupCache::GetSingleton();
748 :
749 23660 : nsCAutoString cachePath(kJSCachePrefix);
750 11830 : rv = PathifyURI(aURI, cachePath);
751 11830 : NS_ENSURE_SUCCESS(rv, rv);
752 :
753 11830 : if (cache) {
754 7785 : rv = ReadCachedScript(cache, cachePath, cx, &script);
755 7785 : if (NS_SUCCEEDED(rv)) {
756 541 : LOG(("Successfully loaded %s from startupcache\n", nativePath.get()));
757 : } else {
758 : // This is ok, it just means the script is not yet in the
759 : // cache. Could mean that the cache was corrupted and got removed,
760 : // but either way we're going to write this out.
761 7244 : writeToCache = true;
762 : }
763 : }
764 :
765 11830 : if (!script) {
766 : // The script wasn't in the cache , so compile it now.
767 11289 : LOG(("Slow loading %s\n", nativePath.get()));
768 :
769 : // If |exception| is non-null, then our caller wants us to propagate
770 : // any exceptions out to our caller. Ensure that the engine doesn't
771 : // eagerly report the exception.
772 11289 : uint32_t oldopts = JS_GetOptions(cx);
773 : JS_SetOptions(cx, oldopts | JSOPTION_NO_SCRIPT_RVAL |
774 11289 : (exception ? JSOPTION_DONT_REPORT_UNCAUGHT : 0));
775 :
776 11289 : if (realFile) {
777 : #ifdef HAVE_PR_MEMMAP
778 : PRInt64 fileSize;
779 11238 : rv = aComponentFile->GetFileSize(&fileSize);
780 11238 : if (NS_FAILED(rv)) {
781 1 : JS_SetOptions(cx, oldopts);
782 1 : return rv;
783 : }
784 :
785 : PRInt64 maxSize;
786 11237 : LL_UI2L(maxSize, PR_UINT32_MAX);
787 11237 : if (LL_CMP(fileSize, >, maxSize)) {
788 0 : NS_ERROR("file too large");
789 0 : JS_SetOptions(cx, oldopts);
790 0 : return NS_ERROR_FAILURE;
791 : }
792 :
793 : PRFileDesc *fileHandle;
794 11237 : rv = aComponentFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
795 11237 : if (NS_FAILED(rv)) {
796 0 : JS_SetOptions(cx, oldopts);
797 0 : return NS_ERROR_FILE_NOT_FOUND;
798 : }
799 :
800 : // Make sure the file is closed, no matter how we return.
801 22474 : FileAutoCloser fileCloser(fileHandle);
802 :
803 : PRFileMap *map = PR_CreateFileMap(fileHandle, fileSize,
804 11237 : PR_PROT_READONLY);
805 11237 : if (!map) {
806 0 : NS_ERROR("Failed to create file map");
807 0 : JS_SetOptions(cx, oldopts);
808 0 : return NS_ERROR_FAILURE;
809 : }
810 :
811 : // Make sure the file map is closed, no matter how we return.
812 22474 : FileMapAutoCloser mapCloser(map);
813 :
814 : PRUint32 fileSize32;
815 11237 : LL_L2UI(fileSize32, fileSize);
816 :
817 11237 : char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
818 11237 : if (!buf) {
819 0 : NS_WARNING("Failed to map file");
820 0 : JS_SetOptions(cx, oldopts);
821 0 : return NS_ERROR_FAILURE;
822 : }
823 :
824 : script = JS_CompileScriptForPrincipalsVersion(cx, global,
825 11237 : nsJSPrincipals::get(mSystemPrincipal),
826 : buf, fileSize32, nativePath.get(), 1,
827 22474 : JSVERSION_LATEST);
828 :
829 22474 : PR_MemUnmap(buf, fileSize32);
830 :
831 : #else /* HAVE_PR_MEMMAP */
832 :
833 : /**
834 : * No memmap implementation, so fall back to
835 : * reading in the file
836 : */
837 :
838 : FILE *fileHandle;
839 : rv = aComponentFile->OpenANSIFileDesc("r", &fileHandle);
840 : if (NS_FAILED(rv)) {
841 : JS_SetOptions(cx, oldopts);
842 : return NS_ERROR_FILE_NOT_FOUND;
843 : }
844 :
845 : // Ensure file fclose
846 : ANSIFileAutoCloser fileCloser(fileHandle);
847 :
848 : PRInt64 len;
849 : rv = aComponentFile->GetFileSize(&len);
850 : if (NS_FAILED(rv) || len < 0) {
851 : NS_WARNING("Failed to get file size");
852 : JS_SetOptions(cx, oldopts);
853 : return NS_ERROR_FAILURE;
854 : }
855 :
856 : char *buf = (char *) malloc(len * sizeof(char));
857 : if (!buf) {
858 : JS_SetOptions(cx, oldopts);
859 : return NS_ERROR_FAILURE;
860 : }
861 :
862 : size_t rlen = fread(buf, 1, len, fileHandle);
863 : if (rlen != (PRUint64)len) {
864 : free(buf);
865 : JS_SetOptions(cx, oldopts);
866 : NS_WARNING("Failed to read file");
867 : return NS_ERROR_FAILURE;
868 : }
869 : script = JS_CompileScriptForPrincipalsVersion(cx, global,
870 : nsJSPrincipals::get(mSystemPrincipal),
871 : buf, rlen, nativePath.get(), 1,
872 : JSVERSION_LATEST);
873 :
874 : free(buf);
875 :
876 : #endif /* HAVE_PR_MEMMAP */
877 : } else {
878 102 : nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
879 51 : NS_ENSURE_SUCCESS(rv, rv);
880 :
881 102 : nsCOMPtr<nsIChannel> scriptChannel;
882 51 : rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(scriptChannel));
883 51 : NS_ENSURE_SUCCESS(rv, rv);
884 :
885 102 : nsCOMPtr<nsIInputStream> scriptStream;
886 51 : rv = scriptChannel->Open(getter_AddRefs(scriptStream));
887 51 : NS_ENSURE_SUCCESS(rv, rv);
888 :
889 : PRUint32 len, bytesRead;
890 :
891 51 : rv = scriptStream->Available(&len);
892 51 : NS_ENSURE_SUCCESS(rv, rv);
893 51 : if (!len)
894 0 : return NS_ERROR_FAILURE;
895 :
896 : /* malloc an internal buf the size of the file */
897 153 : nsAutoArrayPtr<char> buf(new char[len + 1]);
898 51 : if (!buf)
899 0 : return NS_ERROR_OUT_OF_MEMORY;
900 :
901 : /* read the file in one swoop */
902 51 : rv = scriptStream->Read(buf, len, &bytesRead);
903 51 : if (bytesRead != len)
904 0 : return NS_BASE_STREAM_OSERROR;
905 :
906 51 : buf[len] = '\0';
907 :
908 : script = JS_CompileScriptForPrincipalsVersion(cx, global,
909 51 : nsJSPrincipals::get(mSystemPrincipal),
910 : buf, bytesRead, nativePath.get(), 1,
911 153 : JSVERSION_LATEST);
912 : }
913 : // Propagate the exception, if one exists. Also, don't leave the stale
914 : // exception on this context.
915 11288 : JS_SetOptions(cx, oldopts);
916 11288 : if (!script && exception) {
917 2 : JS_GetPendingException(cx, exception);
918 2 : JS_ClearPendingException(cx);
919 : }
920 : }
921 :
922 11829 : if (!script) {
923 : #ifdef DEBUG_shaver_off
924 : fprintf(stderr, "mJCL: script compilation of %s FAILED\n",
925 : nativePath.get());
926 : #endif
927 2 : return NS_ERROR_FAILURE;
928 : }
929 :
930 : #ifdef DEBUG_shaver_off
931 : fprintf(stderr, "mJCL: compiled JS component %s\n",
932 : nativePath.get());
933 : #endif
934 :
935 11827 : if (writeToCache) {
936 : // We successfully compiled the script, so cache it.
937 7244 : rv = WriteCachedScript(cache, cachePath, cx, script);
938 :
939 : // Don't treat failure to write as fatal, since we might be working
940 : // with a read-only cache.
941 7244 : if (NS_SUCCEEDED(rv)) {
942 7244 : LOG(("Successfully wrote to cache\n"));
943 : } else {
944 0 : LOG(("Failed to write to cache\n"));
945 : }
946 : }
947 :
948 : // Assign aGlobal here so that it's available to recursive imports.
949 : // See bug 384168.
950 11827 : *aGlobal = global;
951 :
952 11827 : uint32_t oldopts = JS_GetOptions(cx);
953 : JS_SetOptions(cx, oldopts |
954 11827 : (exception ? JSOPTION_DONT_REPORT_UNCAUGHT : 0));
955 11827 : bool ok = JS_ExecuteScriptVersion(cx, global, script, NULL, JSVERSION_LATEST);
956 11827 : JS_SetOptions(cx, oldopts);
957 :
958 11827 : if (!ok) {
959 : #ifdef DEBUG_shaver_off
960 : fprintf(stderr, "mJCL: failed to execute %s\n", nativePath.get());
961 : #endif
962 2 : if (exception) {
963 2 : JS_GetPendingException(cx, exception);
964 2 : JS_ClearPendingException(cx);
965 : }
966 2 : *aGlobal = nsnull;
967 2 : return NS_ERROR_FAILURE;
968 : }
969 :
970 : /* Freed when we remove from the table. */
971 11825 : *aLocation = ToNewCString(nativePath);
972 11825 : if (!*aLocation) {
973 0 : *aGlobal = nsnull;
974 0 : return NS_ERROR_OUT_OF_MEMORY;
975 : }
976 :
977 11825 : JS_AddNamedObjectRoot(cx, aGlobal, *aLocation);
978 11825 : return NS_OK;
979 : }
980 :
981 : /* static */ PLDHashOperator
982 2063 : mozJSComponentLoader::ClearModules(const nsACString& key, ModuleEntry*& entry, void* cx)
983 : {
984 2063 : entry->Clear();
985 2063 : return PL_DHASH_REMOVE;
986 : }
987 :
988 : void
989 965 : mozJSComponentLoader::UnloadModules()
990 : {
991 965 : mInitialized = false;
992 :
993 965 : mInProgressImports.Clear();
994 965 : mImports.Clear();
995 :
996 965 : mModules.Enumerate(ClearModules, NULL);
997 :
998 : // Destroying our context will force a GC.
999 965 : JS_DestroyContext(mContext);
1000 965 : mContext = nsnull;
1001 :
1002 965 : mRuntimeService = nsnull;
1003 965 : mContextStack = nsnull;
1004 : #ifdef DEBUG_shaver_off
1005 : fprintf(stderr, "mJCL: UnloadAll(%d)\n", aWhen);
1006 : #endif
1007 965 : }
1008 :
1009 : NS_IMETHODIMP
1010 45915 : mozJSComponentLoader::Import(const nsACString& registryLocation,
1011 : const JS::Value& targetObj,
1012 : JSContext* cx,
1013 : PRUint8 optionalArgc,
1014 : JS::Value* retval)
1015 : {
1016 : NS_TIME_FUNCTION_FMT("%s (line %d) (file: %s)", MOZ_FUNCTION_NAME,
1017 : __LINE__, registryLocation.BeginReading());
1018 :
1019 91830 : JSAutoRequest ar(cx);
1020 :
1021 45915 : JSObject *targetObject = nsnull;
1022 :
1023 45915 : if (optionalArgc) {
1024 : // The caller passed in the optional second argument. Get it.
1025 4248 : if (!JSVAL_IS_OBJECT(targetObj)) {
1026 : return ReportOnCaller(cx, ERROR_SCOPE_OBJ,
1027 1 : PromiseFlatCString(registryLocation).get());
1028 : }
1029 4247 : targetObject = JSVAL_TO_OBJECT(targetObj);
1030 : } else {
1031 : // Our targetObject is the caller's global object. Find it by
1032 : // walking the calling object's parent chain.
1033 : nsresult rv;
1034 : nsCOMPtr<nsIXPConnect> xpc =
1035 83334 : do_GetService(kXPConnectServiceContractID, &rv);
1036 41667 : NS_ENSURE_SUCCESS(rv, rv);
1037 :
1038 41667 : nsAXPCNativeCallContext *cc = nsnull;
1039 41667 : rv = xpc->GetCurrentNativeCallContext(&cc);
1040 41667 : NS_ENSURE_SUCCESS(rv, rv);
1041 :
1042 83334 : nsCOMPtr<nsIXPConnectWrappedNative> wn;
1043 41667 : rv = cc->GetCalleeWrapper(getter_AddRefs(wn));
1044 41667 : NS_ENSURE_SUCCESS(rv, rv);
1045 :
1046 41667 : wn->GetJSObject(&targetObject);
1047 41667 : if (!targetObject) {
1048 0 : NS_ERROR("null calling object");
1049 0 : return NS_ERROR_FAILURE;
1050 : }
1051 :
1052 83334 : targetObject = JS_GetGlobalForObject(cx, targetObject);
1053 : }
1054 :
1055 91828 : JSAutoEnterCompartment ac;
1056 45914 : if (targetObject && !ac.enter(cx, targetObject)) {
1057 0 : NS_ERROR("can't enter compartment");
1058 0 : return NS_ERROR_FAILURE;
1059 : }
1060 :
1061 45914 : JSObject *globalObj = nsnull;
1062 45914 : nsresult rv = ImportInto(registryLocation, targetObject, cx, &globalObj);
1063 :
1064 45914 : if (globalObj && !JS_WrapObject(cx, &globalObj)) {
1065 0 : NS_ERROR("can't wrap return value");
1066 0 : return NS_ERROR_FAILURE;
1067 : }
1068 :
1069 45914 : *retval = OBJECT_TO_JSVAL(globalObj);
1070 :
1071 45914 : return rv;
1072 : }
1073 :
1074 : /* [noscript] JSObjectPtr importInto(in AUTF8String registryLocation,
1075 : in JSObjectPtr targetObj); */
1076 : NS_IMETHODIMP
1077 0 : mozJSComponentLoader::ImportInto(const nsACString & aLocation,
1078 : JSObject * targetObj,
1079 : nsAXPCNativeCallContext * cc,
1080 : JSObject * *_retval)
1081 : {
1082 : JSContext *callercx;
1083 0 : nsresult rv = cc->GetJSContext(&callercx);
1084 0 : NS_ENSURE_SUCCESS(rv, rv);
1085 0 : return ImportInto(aLocation, targetObj, callercx, _retval);
1086 : }
1087 :
1088 : nsresult
1089 45914 : mozJSComponentLoader::ImportInto(const nsACString & aLocation,
1090 : JSObject * targetObj,
1091 : JSContext * callercx,
1092 : JSObject * *_retval)
1093 : {
1094 : nsresult rv;
1095 45914 : *_retval = nsnull;
1096 :
1097 45914 : if (!mInitialized) {
1098 870 : rv = ReallyInit();
1099 870 : NS_ENSURE_SUCCESS(rv, rv);
1100 : }
1101 :
1102 91828 : nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
1103 45914 : NS_ENSURE_SUCCESS(rv, rv);
1104 :
1105 : // Get the URI.
1106 91828 : nsCOMPtr<nsIURI> resURI;
1107 45914 : rv = ioService->NewURI(aLocation, nsnull, nsnull, getter_AddRefs(resURI));
1108 45914 : NS_ENSURE_SUCCESS(rv, rv);
1109 :
1110 : // figure out the resolved URI
1111 91828 : nsCOMPtr<nsIChannel> scriptChannel;
1112 45914 : rv = ioService->NewChannelFromURI(resURI, getter_AddRefs(scriptChannel));
1113 45914 : NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
1114 :
1115 91826 : nsCOMPtr<nsIURI> resolvedURI;
1116 45913 : rv = scriptChannel->GetURI(getter_AddRefs(resolvedURI));
1117 45913 : NS_ENSURE_SUCCESS(rv, rv);
1118 :
1119 : // get the JAR if there is one
1120 91826 : nsCOMPtr<nsIJARURI> jarURI;
1121 45913 : jarURI = do_QueryInterface(resolvedURI, &rv);
1122 91826 : nsCOMPtr<nsIFileURL> baseFileURL;
1123 45913 : if (NS_SUCCEEDED(rv)) {
1124 202 : nsCOMPtr<nsIURI> baseURI;
1125 303 : while (jarURI) {
1126 101 : jarURI->GetJARFile(getter_AddRefs(baseURI));
1127 101 : jarURI = do_QueryInterface(baseURI, &rv);
1128 : }
1129 101 : baseFileURL = do_QueryInterface(baseURI, &rv);
1130 101 : NS_ENSURE_SUCCESS(rv, rv);
1131 : } else {
1132 45812 : baseFileURL = do_QueryInterface(resolvedURI, &rv);
1133 45812 : NS_ENSURE_SUCCESS(rv, rv);
1134 : }
1135 :
1136 91826 : nsCOMPtr<nsIFile> sourceFile;
1137 45913 : rv = baseFileURL->GetFile(getter_AddRefs(sourceFile));
1138 45913 : NS_ENSURE_SUCCESS(rv, rv);
1139 :
1140 91826 : nsCOMPtr<nsILocalFile> sourceLocalFile;
1141 45913 : sourceLocalFile = do_QueryInterface(sourceFile, &rv);
1142 45913 : NS_ENSURE_SUCCESS(rv, rv);
1143 :
1144 91826 : nsCAutoString key;
1145 45913 : rv = resolvedURI->GetSpec(key);
1146 45913 : NS_ENSURE_SUCCESS(rv, rv);
1147 :
1148 : ModuleEntry* mod;
1149 91826 : nsAutoPtr<ModuleEntry> newEntry;
1150 45913 : if (!mImports.Get(key, &mod) && !mInProgressImports.Get(key, &mod)) {
1151 9767 : newEntry = new ModuleEntry;
1152 9767 : if (!newEntry || !mInProgressImports.Put(key, newEntry))
1153 0 : return NS_ERROR_OUT_OF_MEMORY;
1154 :
1155 19534 : JS::Anchor<jsval> exception(JSVAL_VOID);
1156 9767 : rv = GlobalForLocation(sourceLocalFile, resURI, &newEntry->global,
1157 19534 : &newEntry->location, &exception.get());
1158 :
1159 9767 : mInProgressImports.Remove(key);
1160 :
1161 9767 : if (NS_FAILED(rv)) {
1162 5 : *_retval = nsnull;
1163 :
1164 5 : if (!JSVAL_IS_VOID(exception.get())) {
1165 : // An exception was thrown during compilation. Propagate it
1166 : // out to our caller so they can report it.
1167 4 : if (!JS_WrapValue(callercx, &exception.get()))
1168 0 : return NS_ERROR_OUT_OF_MEMORY;
1169 4 : JS_SetPendingException(callercx, exception.get());
1170 4 : return NS_OK;
1171 : }
1172 :
1173 : // Something failed, but we don't know what it is, guess.
1174 1 : return NS_ERROR_FILE_NOT_FOUND;
1175 : }
1176 :
1177 19529 : mod = newEntry;
1178 : }
1179 :
1180 45908 : NS_ASSERTION(mod->global, "Import table contains entry with no global");
1181 45908 : *_retval = mod->global;
1182 :
1183 : jsval symbols;
1184 45908 : if (targetObj) {
1185 91810 : JSCLContextHelper cxhelper(this);
1186 :
1187 91810 : JSAutoEnterCompartment ac;
1188 45905 : if (!ac.enter(mContext, mod->global))
1189 0 : return NS_ERROR_FAILURE;
1190 :
1191 45905 : if (!JS_GetProperty(mContext, mod->global,
1192 45905 : "EXPORTED_SYMBOLS", &symbols)) {
1193 : return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT,
1194 0 : PromiseFlatCString(aLocation).get());
1195 : }
1196 :
1197 45905 : JSObject *symbolsObj = nsnull;
1198 91809 : if (!JSVAL_IS_OBJECT(symbols) ||
1199 : !(symbolsObj = JSVAL_TO_OBJECT(symbols)) ||
1200 45904 : !JS_IsArrayObject(mContext, symbolsObj)) {
1201 : return ReportOnCaller(cxhelper, ERROR_NOT_AN_ARRAY,
1202 1 : PromiseFlatCString(aLocation).get());
1203 : }
1204 :
1205 : // Iterate over symbols array, installing symbols on targetObj:
1206 :
1207 45904 : uint32_t symbolCount = 0;
1208 45904 : if (!JS_GetArrayLength(mContext, symbolsObj, &symbolCount)) {
1209 : return ReportOnCaller(cxhelper, ERROR_GETTING_ARRAY_LENGTH,
1210 0 : PromiseFlatCString(aLocation).get());
1211 : }
1212 :
1213 : #ifdef DEBUG
1214 91808 : nsCAutoString logBuffer;
1215 : #endif
1216 :
1217 255283 : for (uint32_t i = 0; i < symbolCount; ++i) {
1218 : jsval val;
1219 : jsid symbolId;
1220 :
1221 628139 : if (!JS_GetElement(mContext, symbolsObj, i, &val) ||
1222 209380 : !JSVAL_IS_STRING(val) ||
1223 209379 : !JS_ValueToId(mContext, val, &symbolId)) {
1224 : return ReportOnCaller(cxhelper, ERROR_ARRAY_ELEMENT,
1225 1 : PromiseFlatCString(aLocation).get(), i);
1226 : }
1227 :
1228 209379 : if (!JS_GetPropertyById(mContext, mod->global, symbolId, &val)) {
1229 0 : JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
1230 0 : if (!bytes)
1231 0 : return NS_ERROR_FAILURE;
1232 : return ReportOnCaller(cxhelper, ERROR_GETTING_SYMBOL,
1233 0 : PromiseFlatCString(aLocation).get(),
1234 0 : bytes.ptr());
1235 : }
1236 :
1237 418758 : JSAutoEnterCompartment target_ac;
1238 :
1239 628137 : if (!target_ac.enter(mContext, targetObj) ||
1240 209379 : !JS_WrapValue(mContext, &val) ||
1241 209379 : !JS_SetPropertyById(mContext, targetObj, symbolId, &val)) {
1242 0 : JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
1243 0 : if (!bytes)
1244 0 : return NS_ERROR_FAILURE;
1245 : return ReportOnCaller(cxhelper, ERROR_SETTING_SYMBOL,
1246 0 : PromiseFlatCString(aLocation).get(),
1247 0 : bytes.ptr());
1248 : }
1249 : #ifdef DEBUG
1250 209379 : if (i == 0) {
1251 42666 : logBuffer.AssignLiteral("Installing symbols [ ");
1252 : }
1253 628137 : JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
1254 209379 : if (!!bytes)
1255 209379 : logBuffer.Append(bytes.ptr());
1256 209379 : logBuffer.AppendLiteral(" ");
1257 209379 : if (i == symbolCount - 1) {
1258 42666 : LOG(("%s] from %s\n", logBuffer.get(),
1259 : PromiseFlatCString(aLocation).get()));
1260 : }
1261 : #endif
1262 : }
1263 : }
1264 :
1265 : // Cache this module for later
1266 45906 : if (newEntry) {
1267 9760 : if (!mImports.Put(key, newEntry))
1268 0 : return NS_ERROR_OUT_OF_MEMORY;
1269 9760 : newEntry.forget();
1270 : }
1271 :
1272 45906 : return NS_OK;
1273 : }
1274 :
1275 : NS_IMETHODIMP
1276 1236 : mozJSComponentLoader::Unload(const nsACString & aLocation)
1277 : {
1278 : nsresult rv;
1279 :
1280 1236 : if (!mInitialized) {
1281 0 : return NS_OK;
1282 : }
1283 :
1284 2472 : nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
1285 1236 : NS_ENSURE_SUCCESS(rv, rv);
1286 :
1287 : // Get the URI.
1288 2472 : nsCOMPtr<nsIURI> resURI;
1289 1236 : rv = ioService->NewURI(aLocation, nsnull, nsnull, getter_AddRefs(resURI));
1290 1236 : NS_ENSURE_SUCCESS(rv, rv);
1291 :
1292 : // figure out the resolved URI
1293 2472 : nsCOMPtr<nsIChannel> scriptChannel;
1294 1236 : rv = ioService->NewChannelFromURI(resURI, getter_AddRefs(scriptChannel));
1295 1236 : NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
1296 :
1297 2472 : nsCOMPtr<nsIURI> resolvedURI;
1298 1236 : rv = scriptChannel->GetURI(getter_AddRefs(resolvedURI));
1299 1236 : NS_ENSURE_SUCCESS(rv, rv);
1300 :
1301 2472 : nsCAutoString key;
1302 1236 : rv = resolvedURI->GetSpec(key);
1303 1236 : NS_ENSURE_SUCCESS(rv, rv);
1304 :
1305 : ModuleEntry* mod;
1306 1236 : if (mImports.Get(key, &mod)) {
1307 1236 : mImports.Remove(key);
1308 : }
1309 :
1310 1236 : return NS_OK;
1311 : }
1312 :
1313 : NS_IMETHODIMP
1314 965 : mozJSComponentLoader::Observe(nsISupports *subject, const char *topic,
1315 : const PRUnichar *data)
1316 : {
1317 965 : if (!strcmp(topic, "xpcom-shutdown-loaders")) {
1318 965 : UnloadModules();
1319 : } else {
1320 0 : NS_ERROR("Unexpected observer topic.");
1321 : }
1322 :
1323 965 : return NS_OK;
1324 : }
1325 :
1326 : /* static */ already_AddRefed<nsIFactory>
1327 2118 : mozJSComponentLoader::ModuleEntry::GetFactory(const mozilla::Module& module,
1328 : const mozilla::Module::CIDEntry& entry)
1329 : {
1330 2118 : const ModuleEntry& self = static_cast<const ModuleEntry&>(module);
1331 2118 : NS_ASSERTION(self.getfactoryobj, "Handing out an uninitialized module?");
1332 :
1333 4236 : nsCOMPtr<nsIFactory> f;
1334 2118 : nsresult rv = self.getfactoryobj->Get(*entry.cid, getter_AddRefs(f));
1335 2118 : if (NS_FAILED(rv))
1336 0 : return NULL;
1337 :
1338 2118 : return f.forget();
1339 : }
1340 :
1341 : //----------------------------------------------------------------------
1342 :
1343 59798 : JSCLContextHelper::JSCLContextHelper(mozJSComponentLoader *loader)
1344 : : mContext(loader->mContext),
1345 : mContextStack(loader->mContextStack),
1346 59798 : mBuf(nsnull)
1347 : {
1348 59798 : mContextStack->Push(mContext);
1349 59798 : JS_BeginRequest(mContext);
1350 59798 : }
1351 :
1352 59798 : JSCLContextHelper::~JSCLContextHelper()
1353 : {
1354 59798 : if (mContextStack) {
1355 59798 : JS_EndRequest(mContext);
1356 :
1357 59798 : mContextStack->Pop(nsnull);
1358 :
1359 59798 : JSContext* cx = nsnull;
1360 59798 : mContextStack->Peek(&cx);
1361 :
1362 59798 : mContextStack = nsnull;
1363 :
1364 59798 : if (cx && mBuf) {
1365 2 : JS_ReportError(cx, mBuf);
1366 : }
1367 : }
1368 :
1369 59798 : if (mBuf) {
1370 2 : JS_smprintf_free(mBuf);
1371 : }
1372 59798 : }
1373 :
1374 : void
1375 2 : JSCLContextHelper::reportErrorAfterPop(char *buf)
1376 : {
1377 2 : NS_ASSERTION(!mBuf, "Already called reportErrorAfterPop");
1378 2 : mBuf = buf;
1379 2 : }
|