LCOV - code coverage report
Current view: directory - js/xpconnect/loader - mozJSComponentLoader.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 553 456 82.5 %
Date: 2012-06-02 Functions: 35 33 94.3 %

       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 : }

Generated by: LCOV version 1.7