1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16 * The Original Code is Mozilla Communicator client code, released
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.
25 * Mike Shaver <shaver@zeroknowledge.com>
26 * John Bandhauer <jband@netscape.com>
28 * Robert Ginda <rginda@netscape.com>
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.
42 * ***** END LICENSE BLOCK ***** */
53 #include "nsAutoPtr.h"
54 #include "nsICategoryManager.h"
55 #include "nsIComponentManager.h"
56 #include "mozilla/Module.h"
57 #include "nsILocalFile.h"
58 #include "nsIServiceManager.h"
59 #include "nsISupports.h"
60 #include "mozJSComponentLoader.h"
61 #include "nsIJSRuntimeService.h"
62 #include "nsIJSContextStack.h"
63 #include "nsIXPConnect.h"
66 #include "nsIObserverService.h"
67 #include "nsIXPCScriptable.h"
69 #ifndef XPCONNECT_STANDALONE
70 #include "nsIScriptSecurityManager.h"
72 #include "nsIFileURL.h"
73 #include "nsIJARURI.h"
74 #include "nsNetUtil.h"
77 #include "jscompartment.h"
79 // For reporting errors with the console service
80 #include "nsIScriptError.h"
81 #include "nsIConsoleService.h"
82 #include "nsIStorageStream.h"
83 #include "nsIStringStream.h"
86 #include "nsILocalFileWin.h"
88 #include "xpcprivate.h"
90 #ifdef MOZ_ENABLE_LIBXUL
91 #include "mozilla/scache/StartupCache.h"
92 #include "mozilla/scache/StartupCacheUtils.h"
94 #include "mozilla/Omnijar.h"
98 #include "mozilla/FunctionTimer.h"
100 static const char kJSRuntimeServiceContractID
[] = "@mozilla.org/js/xpc/RuntimeService;1";
101 static const char kXPConnectServiceContractID
[] = "@mozilla.org/js/xpc/XPConnect;1";
102 static const char kObserverServiceContractID
[] = "@mozilla.org/observer-service;1";
104 /* Some platforms don't have an implementation of PR_MemMap(). */
105 #if !defined(XP_BEOS) && !defined(XP_OS2)
106 #define HAVE_PR_MEMMAP
110 * Buffer sizes for serialization and deserialization of scripts.
111 * FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008
113 #define XPC_SERIALIZATION_BUFFER_SIZE (64 * 1024)
114 #define XPC_DESERIALIZATION_BUFFER_SIZE (12 * 8192)
117 // NSPR_LOG_MODULES=JSComponentLoader:5
118 static PRLogModuleInfo
*gJSCLLog
;
121 #define LOG(args) PR_LOG(gJSCLLog, PR_LOG_DEBUG, args)
123 // Components.utils.import error messages
124 #define ERROR_SCOPE_OBJ "%s - Second argument must be an object."
125 #define ERROR_NOT_PRESENT "%s - EXPORTED_SYMBOLS is not present."
126 #define ERROR_NOT_AN_ARRAY "%s - EXPORTED_SYMBOLS is not an array."
127 #define ERROR_GETTING_ARRAY_LENGTH "%s - Error getting array length of EXPORTED_SYMBOLS."
128 #define ERROR_ARRAY_ELEMENT "%s - EXPORTED_SYMBOLS[%d] is not a string."
129 #define ERROR_GETTING_SYMBOL "%s - Could not get symbol '%s'."
130 #define ERROR_SETTING_SYMBOL "%s - Could not set symbol '%s' on target object."
133 mozJSLoaderErrorReporter(JSContext
*cx
, const char *message
, JSErrorReport
*rep
)
137 /* Use the console service to register the error. */
138 nsCOMPtr
<nsIConsoleService
> consoleService
=
139 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
142 * Make an nsIScriptError, populate it with information from this
143 * error, then log it with the console service. The UI can then
144 * poll the service to update the Error console.
146 nsCOMPtr
<nsIScriptError
> errorObject
=
147 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID
);
149 if (consoleService
&& errorObject
) {
151 * Got an error object; prepare appropriate-width versions of
152 * various arguments to it.
154 nsAutoString fileUni
;
155 fileUni
.AssignWithConversion(rep
->filename
);
157 PRUint32 column
= rep
->uctokenptr
- rep
->uclinebuf
;
159 rv
= errorObject
->Init(reinterpret_cast<const PRUnichar
*>
162 reinterpret_cast<const PRUnichar
*>
164 rep
->lineno
, column
, rep
->flags
,
165 "component javascript");
166 if (NS_SUCCEEDED(rv
)) {
167 rv
= consoleService
->LogMessage(errorObject
);
168 if (NS_SUCCEEDED(rv
)) {
169 // We're done! Skip return to fall thru to stderr
170 // printout, for the benefit of those invoking the
171 // browser with -console
178 * If any of the above fails for some reason, fall back to
179 * printing to stderr.
182 fprintf(stderr
, "JS Component Loader: %s %s:%d\n"
184 JSREPORT_IS_WARNING(rep
->flags
) ? "WARNING" : "ERROR",
185 rep
->filename
, rep
->lineno
,
186 message
? message
: "<no message>");
191 Dump(JSContext
*cx
, uintN argc
, jsval
*vp
)
197 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
202 const jschar
*chars
= JS_GetStringCharsAndLength(cx
, str
, &length
);
206 fputs(NS_ConvertUTF16toUTF8(reinterpret_cast<const PRUnichar
*>(chars
)).get(), stderr
);
211 Debug(JSContext
*cx
, uintN argc
, jsval
*vp
)
214 return Dump(cx
, argc
, vp
);
221 Atob(JSContext
*cx
, uintN argc
, jsval
*vp
)
226 return nsXPConnect::Base64Decode(cx
, JS_ARGV(cx
, vp
)[0], &JS_RVAL(cx
, vp
));
230 Btoa(JSContext
*cx
, uintN argc
, jsval
*vp
)
235 return nsXPConnect::Base64Encode(cx
, JS_ARGV(cx
, vp
)[0], &JS_RVAL(cx
, vp
));
238 static JSFunctionSpec gGlobalFun
[] = {
240 {"debug", Debug
, 1,0},
244 {"startCallgrind", js_StartCallgrind
, 0,0},
245 {"stopCallgrind", js_StopCallgrind
, 0,0},
246 {"dumpCallgrind", js_DumpCallgrind
, 1,0},
249 {"startVtune", js_StartVtune
, 1,0},
250 {"stopVtune", js_StopVtune
, 0,0},
251 {"pauseVtune", js_PauseVtune
, 0,0},
252 {"resumeVtune", js_ResumeVtune
, 0,0},
255 {"initEthogram", js_InitEthogram
, 0,0},
256 {"shutdownEthogram", js_ShutdownEthogram
, 0,0},
261 class JSCLContextHelper
264 JSCLContextHelper(mozJSComponentLoader
* loader
);
265 ~JSCLContextHelper() { Pop(); }
269 operator JSContext
*() const {return mContext
;}
274 nsIThreadJSContextStack
* mContextStack
;
276 // prevent copying and assignment
277 JSCLContextHelper(const JSCLContextHelper
&); // not implemented
278 const JSCLContextHelper
& operator=(const JSCLContextHelper
&); // not implemented
282 class JSCLAutoErrorReporterSetter
285 JSCLAutoErrorReporterSetter(JSContext
* cx
, JSErrorReporter reporter
)
286 {mContext
= cx
; mOldReporter
= JS_SetErrorReporter(cx
, reporter
);}
287 ~JSCLAutoErrorReporterSetter()
288 {JS_SetErrorReporter(mContext
, mOldReporter
);}
291 JSErrorReporter mOldReporter
;
292 // prevent copying and assignment
293 JSCLAutoErrorReporterSetter(const JSCLAutoErrorReporterSetter
&); // not implemented
294 const JSCLAutoErrorReporterSetter
& operator=(const JSCLAutoErrorReporterSetter
&); // not implemented
298 OutputError(JSContext
*cx
,
302 char *buf
= JS_vsmprintf(format
, ap
);
304 return NS_ERROR_OUT_OF_MEMORY
;
307 JS_ReportError(cx
, buf
);
308 JS_smprintf_free(buf
);
314 ReportOnCaller(nsAXPCNativeCallContext
*cc
,
315 const char *format
, ...) {
317 return NS_ERROR_FAILURE
;
321 va_start(ap
, format
);
324 JSContext
*callerContext
;
325 rv
= cc
->GetJSContext(&callerContext
);
326 NS_ENSURE_SUCCESS(rv
, rv
);
328 return OutputError(callerContext
, format
, ap
);
332 ReportOnCaller(JSCLContextHelper
&helper
,
333 const char *format
, ...)
336 va_start(ap
, format
);
338 JSContext
*cx
= helper
.Pop();
340 return NS_ERROR_FAILURE
;
343 return OutputError(cx
, format
, ap
);
346 #ifdef MOZ_ENABLE_LIBXUL
348 ReadScriptFromStream(JSContext
*cx
, nsIObjectInputStream
*stream
,
354 nsresult rv
= stream
->Read32(&size
);
355 NS_ENSURE_SUCCESS(rv
, rv
);
358 rv
= stream
->ReadBytes(size
, &data
);
359 NS_ENSURE_SUCCESS(rv
, rv
);
361 JSXDRState
*xdr
= JS_XDRNewMem(cx
, JSXDR_DECODE
);
362 NS_ENSURE_TRUE(xdr
, NS_ERROR_OUT_OF_MEMORY
);
364 xdr
->userdata
= stream
;
365 JS_XDRMemSetData(xdr
, data
, size
);
367 if (!JS_XDRScript(xdr
, script
)) {
368 rv
= NS_ERROR_FAILURE
;
371 // Update data in case ::JS_XDRScript called back into C++ code to
372 // read an XPCOM object.
374 // In that case, the serialization process must have flushed a run
375 // of counted bytes containing JS data at the point where the XPCOM
376 // object starts, after which an encoding C++ callback from the JS
377 // XDR code must have written the XPCOM object directly into the
378 // nsIObjectOutputStream.
380 // The deserialization process will XDR-decode counted bytes up to
381 // but not including the XPCOM object, then call back into C++ to
382 // read the object, then read more counted bytes and hand them off
383 // to the JSXDRState, so more JS data can be decoded.
385 // This interleaving of JS XDR data and XPCOM object data may occur
386 // several times beneath the call to ::JS_XDRScript, above. At the
387 // end of the day, we need to free (via nsMemory) the data owned by
388 // the JSXDRState. So we steal it back, nulling xdr's buffer so it
389 // doesn't get passed to ::JS_free by ::JS_XDRDestroy.
392 data
= static_cast<char*>(JS_XDRMemGetData(xdr
, &length
));
394 JS_XDRMemSetData(xdr
, nsnull
, 0);
398 // If data is null now, it must have been freed while deserializing an
399 // XPCOM object (e.g., a principal) beneath ::JS_XDRScript.
401 nsMemory::Free(data
);
408 WriteScriptToStream(JSContext
*cx
, JSScript
*script
,
409 nsIObjectOutputStream
*stream
)
411 JSXDRState
*xdr
= JS_XDRNewMem(cx
, JSXDR_ENCODE
);
412 NS_ENSURE_TRUE(xdr
, NS_ERROR_OUT_OF_MEMORY
);
414 xdr
->userdata
= stream
;
417 if (JS_XDRScript(xdr
, &script
)) {
418 // Get the encoded JSXDRState data and write it. The JSXDRState owns
419 // this buffer memory and will free it beneath ::JS_XDRDestroy.
421 // If an XPCOM object needs to be written in the midst of the JS XDR
422 // encoding process, the C++ code called back from the JS engine (e.g.,
423 // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data
424 // from the JSXDRState to aStream, then write the object, then return
425 // to JS XDR code with xdr reset so new JS data is encoded at the front
426 // of the xdr's data buffer.
428 // However many XPCOM objects are interleaved with JS XDR data in the
429 // stream, when control returns here from ::JS_XDRScript, we'll have
430 // one last buffer of data to write to aStream.
433 const char* data
= reinterpret_cast<const char*>
434 (JS_XDRMemGetData(xdr
, &size
));
435 NS_ASSERTION(data
, "no decoded JSXDRState data!");
437 rv
= stream
->Write32(size
);
438 if (NS_SUCCEEDED(rv
)) {
439 rv
= stream
->WriteBytes(data
, size
);
442 rv
= NS_ERROR_FAILURE
; // likely to be a principals serialization error
448 #endif // MOZ_ENABLE_LIBXUL
450 mozJSComponentLoader::mozJSComponentLoader()
453 mInitialized(PR_FALSE
)
455 NS_ASSERTION(!sSelf
, "mozJSComponentLoader should be a singleton");
459 gJSCLLog
= PR_NewLogModule("JSComponentLoader");
466 mozJSComponentLoader::~mozJSComponentLoader()
469 NS_ERROR("'xpcom-shutdown-loaders' was not fired before cleaning up mozJSComponentLoader");
476 mozJSComponentLoader
*
477 mozJSComponentLoader::sSelf
;
479 NS_IMPL_ISUPPORTS3(mozJSComponentLoader
,
480 mozilla::ModuleLoader
,
485 mozJSComponentLoader::ReallyInit()
492 * Get the JSRuntime from the runtime svc, if possible.
493 * We keep a reference around, because it's a Bad Thing if the runtime
494 * service gets shut down before we're done. Bad!
497 mRuntimeService
= do_GetService(kJSRuntimeServiceContractID
, &rv
);
499 NS_FAILED(rv
= mRuntimeService
->GetRuntime(&mRuntime
)))
502 mContextStack
= do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
506 // Create our compilation context.
507 mContext
= JS_NewContext(mRuntime
, 256);
509 return NS_ERROR_OUT_OF_MEMORY
;
511 uint32 options
= JS_GetOptions(mContext
);
512 JS_SetOptions(mContext
, options
| JSOPTION_XML
);
514 // Always use the latest js version
515 JS_SetVersion(mContext
, JSVERSION_LATEST
);
517 // Limit C stack consumption to a reasonable 512K
518 JS_SetNativeStackQuota(mContext
, 512 * 1024);
520 #ifndef XPCONNECT_STANDALONE
521 nsCOMPtr
<nsIScriptSecurityManager
> secman
=
522 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
524 return NS_ERROR_FAILURE
;
526 rv
= secman
->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal
));
527 if (NS_FAILED(rv
) || !mSystemPrincipal
)
528 return NS_ERROR_FAILURE
;
531 if (!mModules
.Init(32))
532 return NS_ERROR_OUT_OF_MEMORY
;
533 if (!mImports
.Init(32))
534 return NS_ERROR_OUT_OF_MEMORY
;
535 if (!mInProgressImports
.Init(32))
536 return NS_ERROR_OUT_OF_MEMORY
;
538 nsCOMPtr
<nsIObserverService
> obsSvc
=
539 do_GetService(kObserverServiceContractID
, &rv
);
540 NS_ENSURE_SUCCESS(rv
, rv
);
542 rv
= obsSvc
->AddObserver(this, "xpcom-shutdown-loaders", PR_FALSE
);
543 NS_ENSURE_SUCCESS(rv
, rv
);
545 // Set up localized comparison and string conversion
546 xpc_LocalizeContext(mContext
);
548 #ifdef DEBUG_shaver_off
549 fprintf(stderr
, "mJCL: ReallyInit success!\n");
551 mInitialized
= PR_TRUE
;
557 mozJSComponentLoader::FileKey(nsILocalFile
* aFile
, nsAString
&aResult
)
560 nsAutoString canonicalPath
;
563 nsCOMPtr
<nsILocalFileWin
> winFile
= do_QueryInterface(aFile
, &rv
);
564 NS_ENSURE_SUCCESS(rv
, rv
);
566 winFile
->GetCanonicalPath(canonicalPath
);
568 aFile
->GetPath(canonicalPath
);
571 aResult
= NS_LITERAL_STRING("f");
572 aResult
+= canonicalPath
;
578 mozJSComponentLoader::JarKey(nsILocalFile
* aFile
,
579 const nsACString
&aComponentPath
,
583 nsAutoString canonicalPath
;
586 nsCOMPtr
<nsILocalFileWin
> winFile
= do_QueryInterface(aFile
, &rv
);
587 NS_ENSURE_SUCCESS(rv
, rv
);
589 winFile
->GetCanonicalPath(canonicalPath
);
591 aFile
->GetPath(canonicalPath
);
594 aResult
= NS_LITERAL_STRING("j");
595 aResult
+= canonicalPath
;
596 AppendUTF8toUTF16(aComponentPath
, aResult
);
601 const mozilla::Module
*
602 mozJSComponentLoader::LoadModule(nsILocalFile
* aComponentFile
)
604 nsCOMPtr
<nsIURI
> uri
;
606 NS_GetURLSpecFromActualFile(aComponentFile
, spec
);
608 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), spec
);
612 nsAutoString hashstring
;
613 rv
= FileKey(aComponentFile
, hashstring
);
617 return LoadModuleImpl(aComponentFile
,
622 const mozilla::Module
*
623 mozJSComponentLoader::LoadModuleFromJAR(nsILocalFile
*aJarFile
,
624 const nsACString
&aComponentPath
)
626 #if !defined(XPCONNECT_STANDALONE)
629 nsCAutoString fullSpec
;
633 rv
= aJarFile
->Equals(mozilla::OmnijarPath(), &equal
);
634 if (NS_SUCCEEDED(rv
) && equal
) {
635 fullSpec
= "resource://gre/";
638 nsCAutoString fileSpec
;
639 NS_GetURLSpecFromActualFile(aJarFile
, fileSpec
);
641 fullSpec
+= fileSpec
;
647 fullSpec
+= aComponentPath
;
649 nsCOMPtr
<nsIURI
> uri
;
650 rv
= NS_NewURI(getter_AddRefs(uri
), fullSpec
);
654 nsAutoString hashstring
;
655 rv
= JarKey(aJarFile
, aComponentPath
, hashstring
);
659 return LoadModuleImpl(aJarFile
,
663 return NS_ERROR_NOT_IMPLEMENTED
;
667 const mozilla::Module
*
668 mozJSComponentLoader::LoadModuleImpl(nsILocalFile
* aSourceFile
,
670 nsIURI
* aComponentURI
)
674 #ifdef NS_FUNCTION_TIMER
675 nsCAutoString
spec__("N/A");
676 aComponentURI
->GetSpec(spec__
);
677 NS_TIME_FUNCTION_FMT("%s (line %d) (file: %s)", MOZ_FUNCTION_NAME
,
678 __LINE__
, spec__
.get());
688 if (mModules
.Get(aKey
, &mod
))
691 nsAutoPtr
<ModuleEntry
> entry(new ModuleEntry
);
695 rv
= GlobalForLocation(aSourceFile
, aComponentURI
, &entry
->global
,
696 &entry
->location
, nsnull
);
699 fprintf(stderr
, "GlobalForLocation failed!\n");
704 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(kXPConnectServiceContractID
,
709 nsCOMPtr
<nsIComponentManager
> cm
;
710 rv
= NS_GetComponentManager(getter_AddRefs(cm
));
714 JSCLContextHelper
cx(this);
715 JSAutoEnterCompartment ac
;
716 if (!ac
.enter(cx
, entry
->global
))
720 nsCOMPtr
<nsIXPConnectJSObjectHolder
> cm_holder
;
721 rv
= xpc
->WrapNative(cx
, entry
->global
, cm
,
722 NS_GET_IID(nsIComponentManager
),
723 getter_AddRefs(cm_holder
));
727 fprintf(stderr
, "WrapNative(%p,%p,nsIComponentManager) failed: %x\n",
728 (void *)(JSContext
*)cx
, (void *)mCompMgr
, rv
);
733 rv
= cm_holder
->GetJSObject(&cm_jsobj
);
736 fprintf(stderr
, "GetJSObject of ComponentManager failed\n");
741 JSObject
* file_jsobj
;
742 nsCOMPtr
<nsIXPConnectJSObjectHolder
> file_holder
;
743 rv
= xpc
->WrapNative(cx
, entry
->global
, aSourceFile
,
745 getter_AddRefs(file_holder
));
751 rv
= file_holder
->GetJSObject(&file_jsobj
);
756 JSCLAutoErrorReporterSetter
aers(cx
, mozJSLoaderErrorReporter
);
758 jsval NSGetFactory_val
;
760 if (!JS_GetProperty(cx
, entry
->global
, "NSGetFactory", &NSGetFactory_val
) ||
761 JSVAL_IS_VOID(NSGetFactory_val
)) {
765 if (JS_TypeOfValue(cx
, NSGetFactory_val
) != JSTYPE_FUNCTION
) {
767 aComponentURI
->GetSpec(spec
);
768 JS_ReportError(cx
, "%s has NSGetFactory property that is not a function",
773 JSObject
*jsGetFactoryObj
;
774 if (!JS_ValueToObject(cx
, NSGetFactory_val
, &jsGetFactoryObj
) ||
776 /* XXX report error properly */
780 rv
= xpc
->WrapJS(cx
, jsGetFactoryObj
,
781 NS_GET_IID(xpcIJSGetFactory
), getter_AddRefs(entry
->getfactoryobj
));
783 /* XXX report error properly */
785 fprintf(stderr
, "mJCL: couldn't get nsIModule from jsval\n");
790 // Cache this module for later
791 if (!mModules
.Put(aKey
, entry
))
794 // The hash owns the ModuleEntry now, forget about it
795 return entry
.forget();
798 // Some stack based classes for cleaning up on early return
799 #ifdef HAVE_PR_MEMMAP
803 explicit FileAutoCloser(PRFileDesc
*file
) : mFile(file
) {}
804 ~FileAutoCloser() { PR_Close(mFile
); }
809 class FileMapAutoCloser
812 explicit FileMapAutoCloser(PRFileMap
*map
) : mMap(map
) {}
813 ~FileMapAutoCloser() { PR_CloseFileMap(mMap
); }
819 class JSPrincipalsHolder
822 JSPrincipalsHolder(JSContext
*cx
, JSPrincipals
*principals
)
823 : mCx(cx
), mPrincipals(principals
) {}
824 ~JSPrincipalsHolder() { JSPRINCIPALS_DROP(mCx
, mPrincipals
); }
827 JSPrincipals
*mPrincipals
;
833 JSScriptHolder(JSContext
*cx
, JSScript
*script
)
834 : mCx(cx
), mScript(script
) {}
835 ~JSScriptHolder() { ::JS_DestroyScript(mCx
, mScript
); }
842 * PathifyURI transforms mozilla .js uris into useful zip paths
843 * to make it makes it easier to manipulate startup cache entries
844 * using standard zip tools.
845 * Transformations applied:
846 * * jsloader/<scheme> prefix is used to group mozJSComponentLoader cache entries in
847 * a top-level zip directory.
848 * * In MOZ_OMNIJAR case resource:/// and resource://gre/ URIs refer to the same path
849 * so treat both of them as resource://gre/
850 * * .bin suffix is added to the end of the path to indicate that jsloader/ entries
851 * are binary representations of JS source.
853 * resource://gre/modules/XPCOMUtils.jsm becomes
854 * jsloader/resource/gre/modules/XPCOMUtils.jsm.bin
857 PathifyURI(nsIURI
*in
, nsACString
&out
)
860 nsCAutoString scheme
;
861 nsresult rv
= in
->GetScheme(scheme
);
862 NS_ENSURE_SUCCESS(rv
, rv
);
865 rv
= in
->GetHost(host
);
866 NS_ENSURE_SUCCESS(rv
, rv
);
868 if (scheme
.Equals("resource") && host
.Length() == 0){
877 rv
= in
->GetPath(path
);
878 NS_ENSURE_SUCCESS(rv
, rv
);
885 #ifdef MOZ_ENABLE_LIBXUL
887 mozJSComponentLoader::ReadScript(StartupCache
* cache
, nsIURI
*uri
,
888 JSContext
*cx
, JSScript
**script
)
893 rv
= PathifyURI(uri
, spec
);
894 NS_ENSURE_SUCCESS(rv
, rv
);
896 nsAutoArrayPtr
<char> buf
;
898 rv
= cache
->GetBuffer(spec
.get(), getter_Transfers(buf
),
901 return rv
; // don't warn since NOT_AVAILABLE is an ok error
904 LOG(("Found %s in startupcache\n", spec
.get()));
905 nsCOMPtr
<nsIObjectInputStream
> ois
;
906 rv
= NS_NewObjectInputStreamFromBuffer(buf
, len
, getter_AddRefs(ois
));
907 NS_ENSURE_SUCCESS(rv
, rv
);
910 return ReadScriptFromStream(cx
, ois
, script
);
914 mozJSComponentLoader::WriteScript(StartupCache
* cache
, JSScript
*script
,
915 nsIFile
*component
, nsIURI
*uri
, JSContext
*cx
)
920 rv
= PathifyURI(uri
, spec
);
921 NS_ENSURE_SUCCESS(rv
, rv
);
923 LOG(("Writing %s to startupcache\n", spec
.get()));
924 nsCOMPtr
<nsIObjectOutputStream
> oos
;
925 nsCOMPtr
<nsIStorageStream
> storageStream
;
926 rv
= NS_NewObjectOutputWrappedStorageStream(getter_AddRefs(oos
),
927 getter_AddRefs(storageStream
));
928 NS_ENSURE_SUCCESS(rv
, rv
);
930 rv
= WriteScriptToStream(cx
, script
, oos
);
932 NS_ENSURE_SUCCESS(rv
, rv
);
934 nsAutoArrayPtr
<char> buf
;
936 rv
= NS_NewBufferFromStorageStream(storageStream
, getter_Transfers(buf
),
938 NS_ENSURE_SUCCESS(rv
, rv
);
940 rv
= cache
->PutBuffer(spec
.get(), buf
, len
);
943 #endif //MOZ_ENABLE_LIBXUL
946 mozJSComponentLoader::GlobalForLocation(nsILocalFile
*aComponentFile
,
954 JSPrincipals
* jsPrincipals
= nsnull
;
955 JSCLContextHelper
cx(this);
957 // preserve caller's compartment
958 js::PreserveCompartment
pc(cx
);
960 #ifndef XPCONNECT_STANDALONE
961 rv
= mSystemPrincipal
->GetJSPrincipals(cx
, &jsPrincipals
);
962 NS_ENSURE_SUCCESS(rv
, rv
);
964 JSPrincipalsHolder
princHolder(mContext
, jsPrincipals
);
967 nsCOMPtr
<nsIXPCScriptable
> backstagePass
;
968 rv
= mRuntimeService
->GetBackstagePass(getter_AddRefs(backstagePass
));
969 NS_ENSURE_SUCCESS(rv
, rv
);
971 JSCLAutoErrorReporterSetter
aers(cx
, mozJSLoaderErrorReporter
);
973 nsCOMPtr
<nsIXPConnect
> xpc
=
974 do_GetService(kXPConnectServiceContractID
, &rv
);
975 NS_ENSURE_SUCCESS(rv
, rv
);
977 // Make sure InitClassesWithNewWrappedGlobal() installs the
978 // backstage pass as the global in our compilation context.
979 JS_SetGlobalObject(cx
, nsnull
);
981 nsCOMPtr
<nsIXPConnectJSObjectHolder
> holder
;
982 rv
= xpc
->InitClassesWithNewWrappedGlobal(cx
, backstagePass
,
983 NS_GET_IID(nsISupports
),
987 FLAG_SYSTEM_GLOBAL_OBJECT
,
988 getter_AddRefs(holder
));
989 NS_ENSURE_SUCCESS(rv
, rv
);
992 rv
= holder
->GetJSObject(&global
);
993 NS_ENSURE_SUCCESS(rv
, rv
);
995 JSAutoEnterCompartment ac
;
996 if (!ac
.enter(cx
, global
))
997 return NS_ERROR_FAILURE
;
999 if (!JS_DefineFunctions(cx
, global
, gGlobalFun
) ||
1000 !JS_DefineProfilingFunctions(cx
, global
)) {
1001 return NS_ERROR_FAILURE
;
1004 bool realFile
= false;
1005 // need to be extra careful checking for URIs pointing to files
1006 // EnsureFile may not always get called, especially on resource URIs
1007 // so we need to call GetFile to make sure this is a valid file
1008 nsCOMPtr
<nsIFileURL
> fileURL
= do_QueryInterface(aURI
, &rv
);
1009 nsCOMPtr
<nsIFile
> testFile
;
1010 if (NS_SUCCEEDED(rv
)) {
1011 fileURL
->GetFile(getter_AddRefs(testFile
));
1017 nsCOMPtr
<nsIXPConnectJSObjectHolder
> locationHolder
;
1018 rv
= xpc
->WrapNative(cx
, global
, aComponentFile
,
1019 NS_GET_IID(nsILocalFile
),
1020 getter_AddRefs(locationHolder
));
1021 NS_ENSURE_SUCCESS(rv
, rv
);
1023 JSObject
*locationObj
;
1024 rv
= locationHolder
->GetJSObject(&locationObj
);
1025 NS_ENSURE_SUCCESS(rv
, rv
);
1027 if (!JS_DefineProperty(cx
, global
, "__LOCATION__",
1028 OBJECT_TO_JSVAL(locationObj
), nsnull
, nsnull
, 0))
1029 return NS_ERROR_FAILURE
;
1032 nsCAutoString nativePath
;
1033 // Quick hack to unbust XPCONNECT_STANDALONE.
1034 // This leaves the jsdebugger with a non-URL pathname in the
1035 // XPCONNECT_STANDALONE case - but at least it builds and runs otherwise.
1036 // See: http://bugzilla.mozilla.org/show_bug.cgi?id=121438
1037 #ifdef XPCONNECT_STANDALONE
1038 localFile
->GetNativePath(nativePath
);
1040 rv
= aURI
->GetSpec(nativePath
);
1041 NS_ENSURE_SUCCESS(rv
, rv
);
1044 JSScript
*script
= nsnull
;
1046 #ifdef MOZ_ENABLE_LIBXUL
1047 // Before compiling the script, first check to see if we have it in
1048 // the startupcache. Note: as a rule, startupcache errors are not fatal
1049 // to loading the script, since we can always slow-load.
1051 PRBool writeToCache
= PR_FALSE
;
1052 StartupCache
* cache
= StartupCache::GetSingleton();
1055 rv
= ReadScript(cache
, aURI
, cx
, &script
);
1056 if (NS_SUCCEEDED(rv
)) {
1057 LOG(("Successfully loaded %s from startupcache\n", nativePath
.get()));
1059 // This is ok, it just means the script is not yet in the
1060 // cache. Could mean that the cache was corrupted and got removed,
1061 // but either way we're going to write this out.
1062 writeToCache
= PR_TRUE
;
1068 // The script wasn't in the cache , so compile it now.
1069 LOG(("Slow loading %s\n", nativePath
.get()));
1071 // If |exception| is non-null, then our caller wants us to propagate
1072 // any exceptions out to our caller. Ensure that the engine doesn't
1073 // eagerly report the exception.
1076 oldopts
= JS_GetOptions(cx
);
1077 JS_SetOptions(cx
, oldopts
| JSOPTION_DONT_REPORT_UNCAUGHT
);
1081 #ifdef HAVE_PR_MEMMAP
1083 rv
= aComponentFile
->GetFileSize(&fileSize
);
1084 if (NS_FAILED(rv
)) {
1085 JS_SetOptions(cx
, oldopts
);
1090 LL_UI2L(maxSize
, PR_UINT32_MAX
);
1091 if (LL_CMP(fileSize
, >, maxSize
)) {
1092 NS_ERROR("file too large");
1093 JS_SetOptions(cx
, oldopts
);
1094 return NS_ERROR_FAILURE
;
1097 PRFileDesc
*fileHandle
;
1098 rv
= aComponentFile
->OpenNSPRFileDesc(PR_RDONLY
, 0, &fileHandle
);
1099 if (NS_FAILED(rv
)) {
1100 JS_SetOptions(cx
, oldopts
);
1101 return NS_ERROR_FILE_NOT_FOUND
;
1104 // Make sure the file is closed, no matter how we return.
1105 FileAutoCloser
fileCloser(fileHandle
);
1107 PRFileMap
*map
= PR_CreateFileMap(fileHandle
, fileSize
,
1110 NS_ERROR("Failed to create file map");
1111 JS_SetOptions(cx
, oldopts
);
1112 return NS_ERROR_FAILURE
;
1115 // Make sure the file map is closed, no matter how we return.
1116 FileMapAutoCloser
mapCloser(map
);
1118 PRUint32 fileSize32
;
1119 LL_L2UI(fileSize32
, fileSize
);
1121 char *buf
= static_cast<char*>(PR_MemMap(map
, 0, fileSize32
));
1123 NS_WARNING("Failed to map file");
1124 JS_SetOptions(cx
, oldopts
);
1125 return NS_ERROR_FAILURE
;
1128 script
= JS_CompileScriptForPrincipalsVersion(
1129 cx
, global
, jsPrincipals
, buf
, fileSize32
, nativePath
.get(), 1,
1132 PR_MemUnmap(buf
, fileSize32
);
1134 #else /* HAVE_PR_MEMMAP */
1137 * No memmap implementation, so fall back to using
1138 * JS_CompileFileHandleForPrincipals().
1142 rv
= aComponentFile
->OpenANSIFileDesc("r", &fileHandle
);
1143 if (NS_FAILED(rv
)) {
1144 JS_SetOptions(cx
, oldopts
);
1145 return NS_ERROR_FILE_NOT_FOUND
;
1148 script
= JS_CompileFileHandleForPrincipalsVersion(
1149 cx
, global
, nativePath
.get(), fileHandle
, jsPrincipals
, JSVERSION_LATEST
);
1151 /* JS will close the filehandle after compilation is complete. */
1152 #endif /* HAVE_PR_MEMMAP */
1154 nsCOMPtr
<nsIIOService
> ioService
= do_GetIOService(&rv
);
1155 NS_ENSURE_SUCCESS(rv
, rv
);
1157 nsCOMPtr
<nsIChannel
> scriptChannel
;
1158 rv
= ioService
->NewChannelFromURI(aURI
, getter_AddRefs(scriptChannel
));
1159 NS_ENSURE_SUCCESS(rv
, rv
);
1161 nsCOMPtr
<nsIInputStream
> scriptStream
;
1162 rv
= scriptChannel
->Open(getter_AddRefs(scriptStream
));
1163 NS_ENSURE_SUCCESS(rv
, rv
);
1165 PRUint32 len
, bytesRead
;
1167 rv
= scriptStream
->Available(&len
);
1168 NS_ENSURE_SUCCESS(rv
, rv
);
1170 return NS_ERROR_FAILURE
;
1172 /* malloc an internal buf the size of the file */
1173 nsAutoArrayPtr
<char> buf(new char[len
+ 1]);
1175 return NS_ERROR_OUT_OF_MEMORY
;
1177 /* read the file in one swoop */
1178 rv
= scriptStream
->Read(buf
, len
, &bytesRead
);
1179 if (bytesRead
!= len
)
1180 return NS_BASE_STREAM_OSERROR
;
1184 script
= JS_CompileScriptForPrincipalsVersion(
1185 cx
, global
, jsPrincipals
, buf
, bytesRead
, nativePath
.get(), 1,
1188 // Propagate the exception, if one exists. Also, don't leave the stale
1189 // exception on this context.
1190 // NB: The caller must stick exception into a rooted slot (probably on
1191 // its context) as soon as possible to avoid GC hazards.
1193 JS_SetOptions(cx
, oldopts
);
1195 JS_GetPendingException(cx
, exception
);
1196 JS_ClearPendingException(cx
);
1202 #ifdef DEBUG_shaver_off
1203 fprintf(stderr
, "mJCL: script compilation of %s FAILED\n",
1206 return NS_ERROR_FAILURE
;
1209 // Ensure that we clean up the script on return.
1210 JSScriptHolder
scriptHolder(cx
, script
);
1212 // Flag this script as a system script
1213 // FIXME: BUG 346139: We actually want to flag this exact filename, not
1214 // anything that starts with this filename... Maybe we need a way to do
1215 // that? On the other hand, the fact that this is in our components dir
1216 // means that if someone snuck a malicious file into this dir we're screwed
1217 // anyway... So maybe flagging as a prefix is fine.
1218 xpc
->FlagSystemFilenamePrefix(nativePath
.get(), PR_TRUE
);
1220 #ifdef DEBUG_shaver_off
1221 fprintf(stderr
, "mJCL: compiled JS component %s\n",
1225 #ifdef MOZ_ENABLE_LIBXUL
1227 // We successfully compiled the script, so cache it.
1228 rv
= WriteScript(cache
, script
, aComponentFile
, aURI
, cx
);
1230 // Don't treat failure to write as fatal, since we might be working
1231 // with a read-only cache.
1232 if (NS_SUCCEEDED(rv
)) {
1233 LOG(("Successfully wrote to cache\n"));
1235 LOG(("Failed to write to cache\n"));
1240 // Assign aGlobal here so that it's available to recursive imports.
1245 if (!JS_ExecuteScriptVersion(cx
, global
, script
, &retval
, JSVERSION_LATEST
)) {
1246 #ifdef DEBUG_shaver_off
1247 fprintf(stderr
, "mJCL: failed to execute %s\n", nativePath
.get());
1250 return NS_ERROR_FAILURE
;
1253 /* Freed when we remove from the table. */
1254 *aLocation
= ToNewCString(nativePath
);
1257 return NS_ERROR_OUT_OF_MEMORY
;
1260 JS_AddNamedObjectRoot(cx
, aGlobal
, *aLocation
);
1264 /* static */ PLDHashOperator
1265 mozJSComponentLoader::ClearModules(const nsAString
& key
, ModuleEntry
*& entry
, void* cx
)
1268 return PL_DHASH_REMOVE
;
1272 mozJSComponentLoader::UnloadModules()
1274 mInitialized
= PR_FALSE
;
1276 mInProgressImports
.Clear();
1279 mModules
.Enumerate(ClearModules
, NULL
);
1281 // Destroying our context will force a GC.
1282 JS_DestroyContext(mContext
);
1285 mRuntimeService
= nsnull
;
1286 mContextStack
= nsnull
;
1287 #ifdef DEBUG_shaver_off
1288 fprintf(stderr
, "mJCL: UnloadAll(%d)\n", aWhen
);
1292 /* [JSObject] import (in AUTF8String registryLocation,
1293 [optional] in JSObject targetObj ); */
1295 mozJSComponentLoader::Import(const nsACString
& registryLocation
)
1297 // This function should only be called from JS.
1300 NS_TIME_FUNCTION_FMT("%s (line %d) (file: %s)", MOZ_FUNCTION_NAME
,
1301 __LINE__
, registryLocation
.BeginReading());
1303 nsCOMPtr
<nsIXPConnect
> xpc
=
1304 do_GetService(kXPConnectServiceContractID
, &rv
);
1305 NS_ENSURE_SUCCESS(rv
, rv
);
1307 nsAXPCNativeCallContext
*cc
= nsnull
;
1308 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
1309 NS_ENSURE_SUCCESS(rv
, rv
);
1313 // ensure that we are being call from JS, from this method
1314 nsCOMPtr
<nsIInterfaceInfo
> info
;
1315 rv
= cc
->GetCalleeInterface(getter_AddRefs(info
));
1316 NS_ENSURE_SUCCESS(rv
, rv
);
1317 nsXPIDLCString name
;
1318 info
->GetName(getter_Copies(name
));
1319 NS_ASSERTION(nsCRT::strcmp("nsIXPCComponents_Utils", name
.get()) == 0,
1320 "Components.utils.import must only be called from JS.");
1321 PRUint16 methodIndex
;
1322 const nsXPTMethodInfo
*methodInfo
;
1323 rv
= info
->GetMethodInfoForName("import", &methodIndex
, &methodInfo
);
1324 NS_ENSURE_SUCCESS(rv
, rv
);
1325 PRUint16 calleeIndex
;
1326 rv
= cc
->GetCalleeMethodIndex(&calleeIndex
);
1327 NS_ASSERTION(calleeIndex
== methodIndex
,
1328 "Components.utils.import called from another utils method.");
1332 JSContext
*cx
= nsnull
;
1333 rv
= cc
->GetJSContext(&cx
);
1334 NS_ENSURE_SUCCESS(rv
, rv
);
1336 JSAutoRequest
ar(cx
);
1338 JSObject
*targetObject
= nsnull
;
1341 rv
= cc
->GetArgc(&argc
);
1342 NS_ENSURE_SUCCESS(rv
, rv
);
1345 // The caller passed in the optional second argument. Get it.
1346 jsval
*argv
= nsnull
;
1347 rv
= cc
->GetArgvPtr(&argv
);
1348 NS_ENSURE_SUCCESS(rv
, rv
);
1349 if (!JSVAL_IS_OBJECT(argv
[1])) {
1350 return ReportOnCaller(cc
, ERROR_SCOPE_OBJ
,
1351 PromiseFlatCString(registryLocation
).get());
1353 targetObject
= JSVAL_TO_OBJECT(argv
[1]);
1355 // Our targetObject is the caller's global object. Find it by
1356 // walking the calling object's parent chain.
1358 nsCOMPtr
<nsIXPConnectWrappedNative
> wn
;
1359 rv
= cc
->GetCalleeWrapper(getter_AddRefs(wn
));
1360 NS_ENSURE_SUCCESS(rv
, rv
);
1362 wn
->GetJSObject(&targetObject
);
1363 if (!targetObject
) {
1364 NS_ERROR("null calling object");
1365 return NS_ERROR_FAILURE
;
1368 targetObject
= JS_GetGlobalForObject(cx
, targetObject
);
1371 JSAutoEnterCompartment ac
;
1372 if (targetObject
&& !ac
.enter(cx
, targetObject
)) {
1373 NS_ERROR("can't enter compartment");
1374 return NS_ERROR_FAILURE
;
1377 JSObject
*globalObj
= nsnull
;
1378 rv
= ImportInto(registryLocation
, targetObject
, cc
, &globalObj
);
1380 if (globalObj
&& !JS_WrapObject(cx
, &globalObj
)) {
1381 NS_ERROR("can't wrap return value");
1382 return NS_ERROR_FAILURE
;
1385 jsval
*retval
= nsnull
;
1386 cc
->GetRetValPtr(&retval
);
1388 *retval
= OBJECT_TO_JSVAL(globalObj
);
1393 /* [noscript] JSObjectPtr importInto(in AUTF8String registryLocation,
1394 in JSObjectPtr targetObj); */
1396 mozJSComponentLoader::ImportInto(const nsACString
& aLocation
,
1397 JSObject
* targetObj
,
1398 nsAXPCNativeCallContext
* cc
,
1399 JSObject
* *_retval
)
1404 if (!mInitialized
) {
1406 NS_ENSURE_SUCCESS(rv
, rv
);
1409 nsCOMPtr
<nsIIOService
> ioService
= do_GetIOService(&rv
);
1410 NS_ENSURE_SUCCESS(rv
, rv
);
1413 nsCOMPtr
<nsIURI
> resURI
;
1414 rv
= ioService
->NewURI(aLocation
, nsnull
, nsnull
, getter_AddRefs(resURI
));
1415 NS_ENSURE_SUCCESS(rv
, rv
);
1417 // figure out the resolved URI
1418 nsCOMPtr
<nsIChannel
> scriptChannel
;
1419 rv
= ioService
->NewChannelFromURI(resURI
, getter_AddRefs(scriptChannel
));
1420 NS_ENSURE_SUCCESS(rv
, NS_ERROR_INVALID_ARG
);
1422 nsCOMPtr
<nsIURI
> resolvedURI
;
1423 rv
= scriptChannel
->GetURI(getter_AddRefs(resolvedURI
));
1424 NS_ENSURE_SUCCESS(rv
, rv
);
1426 // get the JAR if there is one
1427 nsCOMPtr
<nsIJARURI
> jarURI
;
1428 jarURI
= do_QueryInterface(resolvedURI
, &rv
);
1429 nsCOMPtr
<nsIFileURL
> baseFileURL
;
1430 nsCAutoString jarEntry
;
1431 if (NS_SUCCEEDED(rv
)) {
1432 nsCOMPtr
<nsIURI
> baseURI
;
1433 rv
= jarURI
->GetJARFile(getter_AddRefs(baseURI
));
1434 NS_ENSURE_SUCCESS(rv
, rv
);
1436 baseFileURL
= do_QueryInterface(baseURI
, &rv
);
1437 NS_ENSURE_SUCCESS(rv
, rv
);
1439 jarURI
->GetJAREntry(jarEntry
);
1440 NS_ENSURE_SUCCESS(rv
, rv
);
1442 baseFileURL
= do_QueryInterface(resolvedURI
, &rv
);
1443 NS_ENSURE_SUCCESS(rv
, rv
);
1446 nsCOMPtr
<nsIFile
> sourceFile
;
1447 rv
= baseFileURL
->GetFile(getter_AddRefs(sourceFile
));
1448 NS_ENSURE_SUCCESS(rv
, rv
);
1450 nsCOMPtr
<nsILocalFile
> sourceLocalFile
;
1451 sourceLocalFile
= do_QueryInterface(sourceFile
, &rv
);
1452 NS_ENSURE_SUCCESS(rv
, rv
);
1455 if (jarEntry
.IsEmpty()) {
1456 rv
= FileKey(sourceLocalFile
, key
);
1458 rv
= JarKey(sourceLocalFile
, jarEntry
, key
);
1460 NS_ENSURE_SUCCESS(rv
, rv
);
1463 nsAutoPtr
<ModuleEntry
> newEntry
;
1464 if (!mImports
.Get(key
, &mod
) && !mInProgressImports
.Get(key
, &mod
)) {
1465 newEntry
= new ModuleEntry
;
1466 if (!newEntry
|| !mInProgressImports
.Put(key
, newEntry
))
1467 return NS_ERROR_OUT_OF_MEMORY
;
1469 jsval exception
= JSVAL_VOID
;
1470 rv
= GlobalForLocation(sourceLocalFile
, resURI
, &newEntry
->global
,
1471 &newEntry
->location
, &exception
);
1473 mInProgressImports
.Remove(key
);
1475 if (NS_FAILED(rv
)) {
1478 if (!JSVAL_IS_VOID(exception
)) {
1479 // An exception was thrown during compilation. Propagate it
1480 // out to our caller so they can report it.
1481 JSContext
*callercx
;
1482 cc
->GetJSContext(&callercx
);
1483 JS_SetPendingException(callercx
, exception
);
1487 // Something failed, but we don't know what it is, guess.
1488 return NS_ERROR_FILE_NOT_FOUND
;
1494 NS_ASSERTION(mod
->global
, "Import table contains entry with no global");
1495 *_retval
= mod
->global
;
1499 JSCLContextHelper
cxhelper(this);
1501 JSAutoEnterCompartment ac
;
1502 if (!ac
.enter(mContext
, mod
->global
))
1503 return NS_ERROR_FAILURE
;
1505 if (!JS_GetProperty(mContext
, mod
->global
,
1506 "EXPORTED_SYMBOLS", &symbols
)) {
1507 return ReportOnCaller(cxhelper
, ERROR_NOT_PRESENT
,
1508 PromiseFlatCString(aLocation
).get());
1511 JSObject
*symbolsObj
= nsnull
;
1512 if (!JSVAL_IS_OBJECT(symbols
) ||
1513 !(symbolsObj
= JSVAL_TO_OBJECT(symbols
)) ||
1514 !JS_IsArrayObject(mContext
, symbolsObj
)) {
1515 return ReportOnCaller(cxhelper
, ERROR_NOT_AN_ARRAY
,
1516 PromiseFlatCString(aLocation
).get());
1519 // Iterate over symbols array, installing symbols on targetObj:
1521 jsuint symbolCount
= 0;
1522 if (!JS_GetArrayLength(mContext
, symbolsObj
, &symbolCount
)) {
1523 return ReportOnCaller(cxhelper
, ERROR_GETTING_ARRAY_LENGTH
,
1524 PromiseFlatCString(aLocation
).get());
1528 nsCAutoString logBuffer
;
1531 for (jsuint i
= 0; i
< symbolCount
; ++i
) {
1535 if (!JS_GetElement(mContext
, symbolsObj
, i
, &val
) ||
1536 !JSVAL_IS_STRING(val
) ||
1537 !JS_ValueToId(mContext
, val
, &symbolId
)) {
1538 return ReportOnCaller(cxhelper
, ERROR_ARRAY_ELEMENT
,
1539 PromiseFlatCString(aLocation
).get(), i
);
1542 if (!JS_GetPropertyById(mContext
, mod
->global
, symbolId
, &val
)) {
1543 JSAutoByteString
bytes(mContext
, JSID_TO_STRING(symbolId
));
1545 return NS_ERROR_FAILURE
;
1546 return ReportOnCaller(cxhelper
, ERROR_GETTING_SYMBOL
,
1547 PromiseFlatCString(aLocation
).get(),
1551 JSAutoEnterCompartment target_ac
;
1553 if (!target_ac
.enter(mContext
, targetObj
) ||
1554 !JS_WrapValue(mContext
, &val
) ||
1555 !JS_SetPropertyById(mContext
, targetObj
, symbolId
, &val
)) {
1556 JSAutoByteString
bytes(mContext
, JSID_TO_STRING(symbolId
));
1558 return NS_ERROR_FAILURE
;
1559 return ReportOnCaller(cxhelper
, ERROR_SETTING_SYMBOL
,
1560 PromiseFlatCString(aLocation
).get(),
1565 logBuffer
.AssignLiteral("Installing symbols [ ");
1567 JSAutoByteString
bytes(mContext
, JSID_TO_STRING(symbolId
));
1569 logBuffer
.Append(bytes
.ptr());
1570 logBuffer
.AppendLiteral(" ");
1571 if (i
== symbolCount
- 1) {
1572 LOG(("%s] from %s\n", PromiseFlatCString(logBuffer
).get(),
1573 PromiseFlatCString(aLocation
).get()));
1579 // Cache this module for later
1581 if (!mImports
.Put(key
, newEntry
))
1582 return NS_ERROR_OUT_OF_MEMORY
;
1590 mozJSComponentLoader::Observe(nsISupports
*subject
, const char *topic
,
1591 const PRUnichar
*data
)
1593 if (!strcmp(topic
, "xpcom-shutdown-loaders")) {
1597 NS_ERROR("Unexpected observer topic.");
1603 /* static */ already_AddRefed
<nsIFactory
>
1604 mozJSComponentLoader::ModuleEntry::GetFactory(const mozilla::Module
& module
,
1605 const mozilla::Module::CIDEntry
& entry
)
1607 const ModuleEntry
& self
= static_cast<const ModuleEntry
&>(module
);
1608 NS_ASSERTION(self
.getfactoryobj
, "Handing out an uninitialized module?");
1610 nsCOMPtr
<nsIFactory
> f
;
1611 nsresult rv
= self
.getfactoryobj
->Get(*entry
.cid
, getter_AddRefs(f
));
1618 //----------------------------------------------------------------------
1620 JSCLContextHelper::JSCLContextHelper(mozJSComponentLoader
*loader
)
1621 : mContext(loader
->mContext
), mContextThread(0),
1622 mContextStack(loader
->mContextStack
)
1624 mContextStack
->Push(mContext
);
1625 mContextThread
= JS_GetContextThread(mContext
);
1626 if (mContextThread
) {
1627 JS_BeginRequest(mContext
);
1631 // Pops the context that was pushed and then returns the context that is now at
1632 // the top of the stack.
1634 JSCLContextHelper::Pop()
1636 JSContext
* cx
= nsnull
;
1637 if (mContextStack
) {
1638 JS_ClearNewbornRoots(mContext
);
1639 if (mContextThread
) {
1640 JS_EndRequest(mContext
);
1643 mContextStack
->Pop(nsnull
);
1644 mContextStack
->Peek(&cx
);
1645 mContextStack
= nsnull
;