LCOV - code coverage report
Current view: directory - dom/base - nsJSEnvironment.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1553 260 16.7 %
Date: 2012-06-02 Functions: 144 34 23.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=78: */
       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.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Mark Hammond <mhammond@skippinet.com.au>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsJSEnvironment.h"
      41                 : #include "nsIScriptGlobalObject.h"
      42                 : #include "nsIScriptObjectPrincipal.h"
      43                 : #include "nsIDOMChromeWindow.h"
      44                 : #include "nsPIDOMWindow.h"
      45                 : #include "nsIScriptSecurityManager.h"
      46                 : #include "nsDOMCID.h"
      47                 : #include "nsIServiceManager.h"
      48                 : #include "nsIXPConnect.h"
      49                 : #include "nsIJSContextStack.h"
      50                 : #include "nsIJSRuntimeService.h"
      51                 : #include "nsCOMPtr.h"
      52                 : #include "nsISupportsPrimitives.h"
      53                 : #include "nsReadableUtils.h"
      54                 : #include "nsJSUtils.h"
      55                 : #include "nsIDocShell.h"
      56                 : #include "nsIDocShellTreeItem.h"
      57                 : #include "nsPresContext.h"
      58                 : #include "nsIConsoleService.h"
      59                 : #include "nsIScriptError.h"
      60                 : #include "nsIInterfaceRequestor.h"
      61                 : #include "nsIInterfaceRequestorUtils.h"
      62                 : #include "nsIPrompt.h"
      63                 : #include "nsIObserverService.h"
      64                 : #include "nsGUIEvent.h"
      65                 : #include "nsThreadUtils.h"
      66                 : #include "nsITimer.h"
      67                 : #include "nsIAtom.h"
      68                 : #include "nsContentUtils.h"
      69                 : #include "nsEventDispatcher.h"
      70                 : #include "nsIContent.h"
      71                 : #include "nsCycleCollector.h"
      72                 : #include "nsNetUtil.h"
      73                 : #include "nsXPCOMCIDInternal.h"
      74                 : #include "nsIXULRuntime.h"
      75                 : 
      76                 : #include "nsDOMClassInfo.h"
      77                 : #include "xpcpublic.h"
      78                 : 
      79                 : #include "jsdbgapi.h"           // for JS_ClearWatchPointsForObject
      80                 : #include "jswrapper.h"
      81                 : #include "jsxdrapi.h"
      82                 : #include "nsIArray.h"
      83                 : #include "nsIObjectInputStream.h"
      84                 : #include "nsIObjectOutputStream.h"
      85                 : #include "nsDOMScriptObjectHolder.h"
      86                 : #include "prmem.h"
      87                 : #include "WrapperFactory.h"
      88                 : #include "nsGlobalWindow.h"
      89                 : #include "nsScriptNameSpaceManager.h"
      90                 : 
      91                 : #include "nsJSPrincipals.h"
      92                 : 
      93                 : #ifdef XP_MACOSX
      94                 : // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
      95                 : #undef check
      96                 : #endif
      97                 : #include "AccessCheck.h"
      98                 : 
      99                 : #ifdef MOZ_JSDEBUGGER
     100                 : #include "jsdIDebuggerService.h"
     101                 : #endif
     102                 : #ifdef MOZ_LOGGING
     103                 : // Force PR_LOGGING so we can get JS strict warnings even in release builds
     104                 : #define FORCE_PR_LOG 1
     105                 : #endif
     106                 : #include "prlog.h"
     107                 : #include "prthread.h"
     108                 : 
     109                 : #include "mozilla/FunctionTimer.h"
     110                 : #include "mozilla/Preferences.h"
     111                 : #include "mozilla/Telemetry.h"
     112                 : 
     113                 : #include "sampler.h"
     114                 : 
     115                 : using namespace mozilla;
     116                 : 
     117                 : const size_t gStackSize = 8192;
     118                 : 
     119                 : #ifdef PR_LOGGING
     120                 : static PRLogModuleInfo* gJSDiagnostics;
     121                 : #endif
     122                 : 
     123                 : // Thank you Microsoft!
     124                 : #ifdef CompareString
     125                 : #undef CompareString
     126                 : #endif
     127                 : 
     128                 : #define NS_SHRINK_GC_BUFFERS_DELAY  4000 // ms
     129                 : 
     130                 : // The amount of time we wait from the first request to GC to actually
     131                 : // doing the first GC.
     132                 : #define NS_FIRST_GC_DELAY           10000 // ms
     133                 : 
     134                 : // Maximum amount of time that should elapse between incremental GC slices
     135                 : #define NS_INTERSLICE_GC_DELAY      100 // ms
     136                 : 
     137                 : // The amount of time we wait between a request to CC (after GC ran)
     138                 : // and doing the actual CC.
     139                 : #define NS_CC_DELAY                 6000 // ms
     140                 : 
     141                 : #define NS_CC_SKIPPABLE_DELAY       400 // ms
     142                 : 
     143                 : // Force a CC after this long if there's anything in the purple buffer.
     144                 : #define NS_CC_FORCED                (2 * 60 * PR_USEC_PER_SEC) // 2 min
     145                 : 
     146                 : // Don't allow an incremental GC to lock out the CC for too long.
     147                 : #define NS_MAX_CC_LOCKEDOUT_TIME    (5 * PR_USEC_PER_SEC) // 5 seconds
     148                 : 
     149                 : // Trigger a CC if the purple buffer exceeds this size when we check it.
     150                 : #define NS_CC_PURPLE_LIMIT          250
     151                 : 
     152                 : #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
     153                 : 
     154                 : // if you add statics here, add them to the list in nsJSRuntime::Startup
     155                 : 
     156                 : static nsITimer *sGCTimer;
     157                 : static nsITimer *sShrinkGCBuffersTimer;
     158                 : static nsITimer *sCCTimer;
     159                 : 
     160                 : static PRTime sLastCCEndTime;
     161                 : 
     162                 : static bool sCCLockedOut;
     163                 : static PRTime sCCLockedOutTime;
     164                 : 
     165                 : static js::GCSliceCallback sPrevGCSliceCallback;
     166                 : 
     167                 : // The number of currently pending document loads. This count isn't
     168                 : // guaranteed to always reflect reality and can't easily as we don't
     169                 : // have an easy place to know when a load ends or is interrupted in
     170                 : // all cases. This counter also gets reset if we end up GC'ing while
     171                 : // we're waiting for a slow page to load. IOW, this count may be 0
     172                 : // even when there are pending loads.
     173                 : static PRUint32 sPendingLoadCount;
     174                 : static bool sLoadingInProgress;
     175                 : 
     176                 : static PRUint32 sCCollectedWaitingForGC;
     177                 : static bool sPostGCEventsToConsole;
     178                 : static PRUint32 sCCTimerFireCount = 0;
     179                 : static PRUint32 sMinForgetSkippableTime = PR_UINT32_MAX;
     180                 : static PRUint32 sMaxForgetSkippableTime = 0;
     181                 : static PRUint32 sTotalForgetSkippableTime = 0;
     182                 : static PRUint32 sRemovedPurples = 0;
     183                 : static PRUint32 sForgetSkippableBeforeCC = 0;
     184                 : static PRUint32 sPreviousSuspectedCount = 0;
     185                 : 
     186                 : static bool sCleanupSinceLastGC = true;
     187                 : static bool sNeedsFullCC = false;
     188                 : 
     189                 : nsScriptNameSpaceManager *gNameSpaceManager;
     190                 : 
     191                 : static nsIJSRuntimeService *sRuntimeService;
     192                 : JSRuntime *nsJSRuntime::sRuntime;
     193                 : 
     194                 : static const char kJSRuntimeServiceContractID[] =
     195                 :   "@mozilla.org/js/xpc/RuntimeService;1";
     196                 : 
     197                 : static PRTime sFirstCollectionTime;
     198                 : 
     199                 : static bool sIsInitialized;
     200                 : static bool sDidShutdown;
     201                 : 
     202                 : static PRInt32 sContextCount;
     203                 : 
     204                 : static PRTime sMaxScriptRunTime;
     205                 : static PRTime sMaxChromeScriptRunTime;
     206                 : 
     207                 : static nsIScriptSecurityManager *sSecurityManager;
     208                 : 
     209                 : // nsMemoryPressureObserver observes the memory-pressure notifications
     210                 : // and forces a garbage collection and cycle collection when it happens, if
     211                 : // the appropriate pref is set.
     212                 : 
     213                 : static bool sGCOnMemoryPressure;
     214                 : 
     215                 : class nsMemoryPressureObserver : public nsIObserver
     216              50 : {
     217                 : public:
     218                 :   NS_DECL_ISUPPORTS
     219                 :   NS_DECL_NSIOBSERVER
     220                 : };
     221                 : 
     222             150 : NS_IMPL_ISUPPORTS1(nsMemoryPressureObserver, nsIObserver)
     223                 : 
     224                 : NS_IMETHODIMP
     225               0 : nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
     226                 :                                   const PRUnichar* aData)
     227                 : {
     228               0 :   if (sGCOnMemoryPressure) {
     229               0 :     nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking);
     230               0 :     nsJSContext::CycleCollectNow();
     231                 :   }
     232               0 :   return NS_OK;
     233                 : }
     234                 : 
     235               0 : class nsRootedJSValueArray {
     236                 : public:
     237               0 :   explicit nsRootedJSValueArray(JSContext *cx) : avr(cx, vals.Length(), vals.Elements()) {}
     238                 : 
     239               0 :   bool SetCapacity(JSContext *cx, size_t capacity) {
     240               0 :     bool ok = vals.SetCapacity(capacity);
     241               0 :     if (!ok)
     242               0 :       return false;
     243                 :     // Values must be safe for the GC to inspect (they must not contain garbage).
     244               0 :     memset(vals.Elements(), 0, vals.Capacity() * sizeof(jsval));
     245               0 :     resetRooter(cx);
     246               0 :     return true;
     247                 :   }
     248                 : 
     249               0 :   jsval *Elements() {
     250               0 :     return vals.Elements();
     251                 :   }
     252                 : 
     253                 : private:
     254               0 :   void resetRooter(JSContext *cx) {
     255               0 :     avr.changeArray(vals.Elements(), vals.Length());
     256               0 :   }
     257                 : 
     258                 :   nsAutoTArray<jsval, 16> vals;
     259                 :   JS::AutoArrayRooter avr;
     260                 : };
     261                 : 
     262                 : /****************************************************************
     263                 :  ************************** AutoFree ****************************
     264                 :  ****************************************************************/
     265                 : 
     266                 : class AutoFree {
     267                 : public:
     268               0 :   AutoFree(void *aPtr) : mPtr(aPtr) {
     269               0 :   }
     270               0 :   ~AutoFree() {
     271               0 :     if (mPtr)
     272               0 :       nsMemory::Free(mPtr);
     273               0 :   }
     274                 :   void Invalidate() {
     275                 :     mPtr = 0;
     276                 :   }
     277                 : private:
     278                 :   void *mPtr;
     279                 : };
     280                 : 
     281                 : // A utility function for script languages to call.  Although it looks small,
     282                 : // the use of nsIDocShell and nsPresContext triggers a huge number of
     283                 : // dependencies that most languages would not otherwise need.
     284                 : // XXXmarkh - This function is mis-placed!
     285                 : bool
     286               0 : NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
     287                 :                      nsScriptErrorEvent *aErrorEvent,
     288                 :                      nsEventStatus *aStatus)
     289                 : {
     290               0 :   bool called = false;
     291               0 :   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobal));
     292               0 :   nsIDocShell *docShell = win ? win->GetDocShell() : nsnull;
     293               0 :   if (docShell) {
     294               0 :     nsRefPtr<nsPresContext> presContext;
     295               0 :     docShell->GetPresContext(getter_AddRefs(presContext));
     296                 : 
     297                 :     static PRInt32 errorDepth; // Recursion prevention
     298               0 :     ++errorDepth;
     299                 : 
     300               0 :     if (presContext && errorDepth < 2) {
     301                 :       // Dispatch() must be synchronous for the recursion block
     302                 :       // (errorDepth) to work.
     303                 :       nsEventDispatcher::Dispatch(win, presContext, aErrorEvent, nsnull,
     304               0 :                                   aStatus);
     305               0 :       called = true;
     306                 :     }
     307               0 :     --errorDepth;
     308                 :   }
     309               0 :   return called;
     310                 : }
     311                 : 
     312                 : class ScriptErrorEvent : public nsRunnable
     313               0 : {
     314                 : public:
     315               0 :   ScriptErrorEvent(nsIScriptGlobalObject* aScriptGlobal,
     316                 :                    nsIPrincipal* aScriptOriginPrincipal,
     317                 :                    PRUint32 aLineNr, PRUint32 aColumn, PRUint32 aFlags,
     318                 :                    const nsAString& aErrorMsg,
     319                 :                    const nsAString& aFileName,
     320                 :                    const nsAString& aSourceLine,
     321                 :                    bool aDispatchEvent,
     322                 :                    PRUint64 aInnerWindowID)
     323                 :     : mScriptGlobal(aScriptGlobal), mOriginPrincipal(aScriptOriginPrincipal),
     324                 :       mLineNr(aLineNr), mColumn(aColumn),
     325                 :     mFlags(aFlags), mErrorMsg(aErrorMsg), mFileName(aFileName),
     326                 :     mSourceLine(aSourceLine), mDispatchEvent(aDispatchEvent),
     327               0 :     mInnerWindowID(aInnerWindowID)
     328               0 :   {}
     329                 : 
     330               0 :   NS_IMETHOD Run()
     331                 :   {
     332               0 :     nsEventStatus status = nsEventStatus_eIgnore;
     333                 :     // First, notify the DOM that we have a script error.
     334               0 :     if (mDispatchEvent) {
     335               0 :       nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
     336               0 :       nsIDocShell* docShell = win ? win->GetDocShell() : nsnull;
     337               0 :       if (docShell &&
     338               0 :           !JSREPORT_IS_WARNING(mFlags) &&
     339               0 :           !sHandlingScriptError) {
     340               0 :         sHandlingScriptError = true; // Recursion prevention
     341                 : 
     342               0 :         nsRefPtr<nsPresContext> presContext;
     343               0 :         docShell->GetPresContext(getter_AddRefs(presContext));
     344                 : 
     345               0 :         if (presContext) {
     346               0 :           nsScriptErrorEvent errorevent(true, NS_LOAD_ERROR);
     347                 : 
     348               0 :           errorevent.fileName = mFileName.get();
     349                 : 
     350               0 :           nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
     351               0 :           NS_ENSURE_STATE(sop);
     352               0 :           nsIPrincipal* p = sop->GetPrincipal();
     353               0 :           NS_ENSURE_STATE(p);
     354                 : 
     355               0 :           bool sameOrigin = !mOriginPrincipal;
     356                 : 
     357               0 :           if (p && !sameOrigin) {
     358               0 :             if (NS_FAILED(p->Subsumes(mOriginPrincipal, &sameOrigin))) {
     359               0 :               sameOrigin = false;
     360                 :             }
     361                 :           }
     362                 : 
     363               0 :           NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
     364               0 :           if (sameOrigin) {
     365               0 :             errorevent.errorMsg = mErrorMsg.get();
     366               0 :             errorevent.lineNr = mLineNr;
     367                 :           } else {
     368               0 :             NS_WARNING("Not same origin error!");
     369               0 :             errorevent.errorMsg = xoriginMsg.get();
     370               0 :             errorevent.lineNr = 0;
     371                 :           }
     372                 : 
     373                 :           nsEventDispatcher::Dispatch(win, presContext, &errorevent, nsnull,
     374               0 :                                       &status);
     375                 :         }
     376                 : 
     377               0 :         sHandlingScriptError = false;
     378                 :       }
     379                 :     }
     380                 : 
     381               0 :     if (status != nsEventStatus_eConsumeNoDefault) {
     382                 :       // Make an nsIScriptError and populate it with information from
     383                 :       // this error.
     384                 :       nsCOMPtr<nsIScriptError> errorObject =
     385               0 :         do_CreateInstance("@mozilla.org/scripterror;1");
     386                 : 
     387               0 :       if (errorObject != nsnull) {
     388               0 :         nsresult rv = NS_ERROR_NOT_AVAILABLE;
     389                 : 
     390                 :         // Set category to chrome or content
     391                 :         nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
     392               0 :           do_QueryInterface(mScriptGlobal);
     393               0 :         NS_ASSERTION(scriptPrincipal, "Global objects must implement "
     394                 :                      "nsIScriptObjectPrincipal");
     395               0 :         nsCOMPtr<nsIPrincipal> systemPrincipal;
     396               0 :         sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
     397                 :         const char * category =
     398               0 :           scriptPrincipal->GetPrincipal() == systemPrincipal
     399                 :           ? "chrome javascript"
     400               0 :           : "content javascript";
     401                 : 
     402               0 :         rv = errorObject->InitWithWindowID(mErrorMsg.get(), mFileName.get(),
     403                 :                                            mSourceLine.get(),
     404                 :                                            mLineNr, mColumn, mFlags,
     405               0 :                                            category, mInnerWindowID);
     406                 : 
     407               0 :         if (NS_SUCCEEDED(rv)) {
     408                 :           nsCOMPtr<nsIConsoleService> consoleService =
     409               0 :             do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
     410               0 :           if (NS_SUCCEEDED(rv)) {
     411               0 :             consoleService->LogMessage(errorObject);
     412                 :           }
     413                 :         }
     414                 :       }
     415                 :     }
     416               0 :     return NS_OK;
     417                 :   }
     418                 : 
     419                 : 
     420                 :   nsCOMPtr<nsIScriptGlobalObject> mScriptGlobal;
     421                 :   nsCOMPtr<nsIPrincipal>          mOriginPrincipal;
     422                 :   PRUint32                        mLineNr;
     423                 :   PRUint32                        mColumn;
     424                 :   PRUint32                        mFlags;
     425                 :   nsString                        mErrorMsg;
     426                 :   nsString                        mFileName;
     427                 :   nsString                        mSourceLine;
     428                 :   bool                            mDispatchEvent;
     429                 :   PRUint64                        mInnerWindowID;
     430                 : 
     431                 :   static bool sHandlingScriptError;
     432                 : };
     433                 : 
     434                 : bool ScriptErrorEvent::sHandlingScriptError = false;
     435                 : 
     436                 : // NOTE: This function could be refactored to use the above.  The only reason
     437                 : // it has not been done is that the code below only fills the error event
     438                 : // after it has a good nsPresContext - whereas using the above function
     439                 : // would involve always filling it.  Is that a concern?
     440                 : void
     441               0 : NS_ScriptErrorReporter(JSContext *cx,
     442                 :                        const char *message,
     443                 :                        JSErrorReport *report)
     444                 : {
     445                 :   // We don't want to report exceptions too eagerly, but warnings in the
     446                 :   // absence of werror are swallowed whole, so report those now.
     447               0 :   if (!JSREPORT_IS_WARNING(report->flags)) {
     448               0 :     JSStackFrame * fp = nsnull;
     449               0 :     while ((fp = JS_FrameIterator(cx, &fp))) {
     450               0 :       if (JS_IsScriptFrame(cx, fp)) {
     451               0 :         return;
     452                 :       }
     453                 :     }
     454                 : 
     455               0 :     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     456               0 :     if (xpc) {
     457               0 :       nsAXPCNativeCallContext *cc = nsnull;
     458               0 :       xpc->GetCurrentNativeCallContext(&cc);
     459               0 :       if (cc) {
     460               0 :         nsAXPCNativeCallContext *prev = cc;
     461               0 :         while (NS_SUCCEEDED(prev->GetPreviousCallContext(&prev)) && prev) {
     462                 :           PRUint16 lang;
     463               0 :           if (NS_SUCCEEDED(prev->GetLanguage(&lang)) &&
     464                 :             lang == nsAXPCNativeCallContext::LANG_JS) {
     465               0 :             return;
     466                 :           }
     467                 :         }
     468                 :       }
     469                 :     }
     470                 :   }
     471                 : 
     472                 :   // XXX this means we are not going to get error reports on non DOM contexts
     473               0 :   nsIScriptContext *context = nsJSUtils::GetDynamicScriptContext(cx);
     474                 : 
     475                 :   // Note: we must do this before running any more code on cx (if cx is the
     476                 :   // dynamic script context).
     477               0 :   ::JS_ClearPendingException(cx);
     478                 : 
     479               0 :   if (context) {
     480               0 :     nsIScriptGlobalObject *globalObject = context->GetGlobalObject();
     481                 : 
     482               0 :     if (globalObject) {
     483               0 :       nsAutoString fileName, msg;
     484               0 :       if (!report->filename) {
     485               0 :         fileName.SetIsVoid(true);
     486                 :       } else {
     487               0 :         fileName.AssignWithConversion(report->filename);
     488                 :       }
     489                 : 
     490                 :       const PRUnichar *m = reinterpret_cast<const PRUnichar*>
     491               0 :                                              (report->ucmessage);
     492               0 :       if (m) {
     493               0 :         msg.Assign(m);
     494                 :       }
     495                 : 
     496               0 :       if (msg.IsEmpty() && message) {
     497               0 :         msg.AssignWithConversion(message);
     498                 :       }
     499                 : 
     500                 : 
     501                 :       /* We do not try to report Out Of Memory via a dom
     502                 :        * event because the dom event handler would encounter
     503                 :        * an OOM exception trying to process the event, and
     504                 :        * then we'd need to generate a new OOM event for that
     505                 :        * new OOM instance -- this isn't pretty.
     506                 :        */
     507               0 :       nsAutoString sourceLine;
     508               0 :       sourceLine.Assign(reinterpret_cast<const PRUnichar*>(report->uclinebuf));
     509               0 :       nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
     510               0 :       PRUint64 innerWindowID = 0;
     511               0 :       if (win) {
     512               0 :         nsCOMPtr<nsPIDOMWindow> innerWin = win->GetCurrentInnerWindow();
     513               0 :         if (innerWin) {
     514               0 :           innerWindowID = innerWin->WindowID();
     515                 :         }
     516                 :       }
     517                 :       nsContentUtils::AddScriptRunner(
     518                 :         new ScriptErrorEvent(globalObject,
     519               0 :                              nsJSPrincipals::get(report->originPrincipals),
     520                 :                              report->lineno,
     521                 :                              report->uctokenptr - report->uclinebuf,
     522                 :                              report->flags, msg, fileName, sourceLine,
     523                 :                              report->errorNumber != JSMSG_OUT_OF_MEMORY,
     524               0 :                              innerWindowID));
     525                 :     }
     526                 :   }
     527                 : 
     528                 : #ifdef DEBUG
     529                 :   // Print it to stderr as well, for the benefit of those invoking
     530                 :   // mozilla with -console.
     531               0 :   nsCAutoString error;
     532               0 :   error.Assign("JavaScript ");
     533               0 :   if (JSREPORT_IS_STRICT(report->flags))
     534               0 :     error.Append("strict ");
     535               0 :   if (JSREPORT_IS_WARNING(report->flags))
     536               0 :     error.Append("warning: ");
     537                 :   else
     538               0 :     error.Append("error: ");
     539               0 :   error.Append(report->filename);
     540               0 :   error.Append(", line ");
     541               0 :   error.AppendInt(report->lineno, 10);
     542               0 :   error.Append(": ");
     543               0 :   if (report->ucmessage) {
     544                 :     AppendUTF16toUTF8(reinterpret_cast<const PRUnichar*>(report->ucmessage),
     545               0 :                       error);
     546                 :   } else {
     547               0 :     error.Append(message);
     548                 :   }
     549                 : 
     550               0 :   fprintf(stderr, "%s\n", error.get());
     551               0 :   fflush(stderr);
     552                 : #endif
     553                 : 
     554                 : #ifdef PR_LOGGING
     555               0 :   if (!gJSDiagnostics)
     556               0 :     gJSDiagnostics = PR_NewLogModule("JSDiagnostics");
     557                 : 
     558               0 :   if (gJSDiagnostics) {
     559               0 :     PR_LOG(gJSDiagnostics,
     560                 :            JSREPORT_IS_WARNING(report->flags) ? PR_LOG_WARNING : PR_LOG_ERROR,
     561                 :            ("file %s, line %u: %s\n%s%s",
     562                 :             report->filename, report->lineno, message,
     563                 :             report->linebuf ? report->linebuf : "",
     564                 :             (report->linebuf &&
     565                 :              report->linebuf[strlen(report->linebuf)-1] != '\n')
     566                 :             ? "\n"
     567                 :             : ""));
     568                 :   }
     569                 : #endif
     570                 : }
     571                 : 
     572                 : #ifdef DEBUG
     573                 : // A couple of useful functions to call when you're debugging.
     574                 : nsGlobalWindow *
     575               0 : JSObject2Win(JSContext *cx, JSObject *obj)
     576                 : {
     577               0 :   nsIXPConnect *xpc = nsContentUtils::XPConnect();
     578               0 :   if (!xpc) {
     579               0 :     return nsnull;
     580                 :   }
     581                 : 
     582               0 :   nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     583               0 :   xpc->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper));
     584               0 :   if (wrapper) {
     585               0 :     nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
     586               0 :     if (win) {
     587                 :       return static_cast<nsGlobalWindow *>
     588               0 :                         (static_cast<nsPIDOMWindow *>(win));
     589                 :     }
     590                 :   }
     591                 : 
     592               0 :   return nsnull;
     593                 : }
     594                 : 
     595                 : void
     596               0 : PrintWinURI(nsGlobalWindow *win)
     597                 : {
     598               0 :   if (!win) {
     599               0 :     printf("No window passed in.\n");
     600               0 :     return;
     601                 :   }
     602                 : 
     603               0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
     604               0 :   if (!doc) {
     605               0 :     printf("No document in the window.\n");
     606                 :     return;
     607                 :   }
     608                 : 
     609               0 :   nsIURI *uri = doc->GetDocumentURI();
     610               0 :   if (!uri) {
     611               0 :     printf("Document doesn't have a URI.\n");
     612                 :     return;
     613                 :   }
     614                 : 
     615               0 :   nsCAutoString spec;
     616               0 :   uri->GetSpec(spec);
     617               0 :   printf("%s\n", spec.get());
     618                 : }
     619                 : 
     620                 : void
     621               0 : PrintWinCodebase(nsGlobalWindow *win)
     622                 : {
     623               0 :   if (!win) {
     624               0 :     printf("No window passed in.\n");
     625               0 :     return;
     626                 :   }
     627                 : 
     628               0 :   nsIPrincipal *prin = win->GetPrincipal();
     629               0 :   if (!prin) {
     630               0 :     printf("Window doesn't have principals.\n");
     631               0 :     return;
     632                 :   }
     633                 : 
     634               0 :   nsCOMPtr<nsIURI> uri;
     635               0 :   prin->GetURI(getter_AddRefs(uri));
     636               0 :   if (!uri) {
     637               0 :     printf("No URI, maybe the system principal.\n");
     638                 :     return;
     639                 :   }
     640                 : 
     641               0 :   nsCAutoString spec;
     642               0 :   uri->GetSpec(spec);
     643               0 :   printf("%s\n", spec.get());
     644                 : }
     645                 : 
     646                 : void
     647               0 : DumpString(const nsAString &str)
     648                 : {
     649               0 :   printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
     650               0 : }
     651                 : #endif
     652                 : 
     653                 : static already_AddRefed<nsIPrompt>
     654               0 : GetPromptFromContext(nsJSContext* ctx)
     655                 : {
     656               0 :   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(ctx->GetGlobalObject()));
     657               0 :   NS_ENSURE_TRUE(win, nsnull);
     658                 : 
     659               0 :   nsIDocShell *docShell = win->GetDocShell();
     660               0 :   NS_ENSURE_TRUE(docShell, nsnull);
     661                 : 
     662               0 :   nsCOMPtr<nsIInterfaceRequestor> ireq(do_QueryInterface(docShell));
     663               0 :   NS_ENSURE_TRUE(ireq, nsnull);
     664                 : 
     665                 :   // Get the nsIPrompt interface from the docshell
     666                 :   nsIPrompt* prompt;
     667               0 :   ireq->GetInterface(NS_GET_IID(nsIPrompt), (void**)&prompt);
     668               0 :   return prompt;
     669                 : }
     670                 : 
     671                 : JSBool
     672               0 : nsJSContext::DOMOperationCallback(JSContext *cx)
     673                 : {
     674                 :   nsresult rv;
     675                 : 
     676                 :   // Get the native context
     677               0 :   nsJSContext *ctx = static_cast<nsJSContext *>(::JS_GetContextPrivate(cx));
     678                 : 
     679               0 :   if (!ctx) {
     680                 :     // Can happen; see bug 355811
     681               0 :     return JS_TRUE;
     682                 :   }
     683                 : 
     684                 :   // XXX Save the operation callback time so we can restore it after the GC,
     685                 :   // because GCing can cause JS to run on our context, causing our
     686                 :   // ScriptEvaluated to be called, and clearing our operation callback time.
     687                 :   // See bug 302333.
     688               0 :   PRTime callbackTime = ctx->mOperationCallbackTime;
     689               0 :   PRTime modalStateTime = ctx->mModalStateTime;
     690                 : 
     691                 :   // Now restore the callback time and count, in case they got reset.
     692               0 :   ctx->mOperationCallbackTime = callbackTime;
     693               0 :   ctx->mModalStateTime = modalStateTime;
     694                 : 
     695               0 :   PRTime now = PR_Now();
     696                 : 
     697               0 :   if (callbackTime == 0) {
     698                 :     // Initialize mOperationCallbackTime to start timing how long the
     699                 :     // script has run
     700               0 :     ctx->mOperationCallbackTime = now;
     701               0 :     return JS_TRUE;
     702                 :   }
     703                 : 
     704               0 :   if (ctx->mModalStateDepth) {
     705                 :     // We're waiting on a modal dialog, nothing more to do here.
     706               0 :     return JS_TRUE;
     707                 :   }
     708                 : 
     709               0 :   PRTime duration = now - callbackTime;
     710                 : 
     711                 :   // Check the amount of time this script has been running, or if the
     712                 :   // dialog is disabled.
     713               0 :   JSObject* global = ::JS_GetGlobalForScopeChain(cx);
     714                 :   bool isTrackingChromeCodeTime =
     715               0 :     global && xpc::AccessCheck::isChrome(js::GetObjectCompartment(global));
     716               0 :   if (duration < (isTrackingChromeCodeTime ?
     717                 :                   sMaxChromeScriptRunTime : sMaxScriptRunTime)) {
     718               0 :     return JS_TRUE;
     719                 :   }
     720                 : 
     721               0 :   if (!nsContentUtils::IsSafeToRunScript()) {
     722                 :     // If it isn't safe to run script, then it isn't safe to bring up the
     723                 :     // prompt (since that will cause the event loop to spin). In this case
     724                 :     // (which is rare), we just stop the script... But report a warning so
     725                 :     // that developers have some idea of what went wrong.
     726                 : 
     727               0 :     JS_ReportWarning(cx, "A long running script was terminated");
     728               0 :     return JS_FALSE;
     729                 :   }
     730                 : 
     731                 :   // If we get here we're most likely executing an infinite loop in JS,
     732                 :   // we'll tell the user about this and we'll give the user the option
     733                 :   // of stopping the execution of the script.
     734               0 :   nsCOMPtr<nsIPrompt> prompt = GetPromptFromContext(ctx);
     735               0 :   NS_ENSURE_TRUE(prompt, JS_FALSE);
     736                 : 
     737                 :   // Check if we should offer the option to debug
     738                 :   JSScript *script;
     739                 :   unsigned lineno;
     740               0 :   JSBool hasFrame = ::JS_DescribeScriptedCaller(cx, &script, &lineno);
     741                 : 
     742               0 :   bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
     743                 : #ifdef MOZ_JSDEBUGGER
     744                 :   // Get the debugger service if necessary.
     745               0 :   if (debugPossible) {
     746               0 :     bool jsds_IsOn = false;
     747               0 :     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
     748               0 :     nsCOMPtr<jsdIExecutionHook> jsdHook;
     749               0 :     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
     750                 : 
     751                 :     // Check if there's a user for the debugger service that's 'on' for us
     752               0 :     if (NS_SUCCEEDED(rv)) {
     753               0 :       jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
     754               0 :       jsds->GetIsOn(&jsds_IsOn);
     755                 :     }
     756                 : 
     757                 :     // If there is a debug handler registered for this runtime AND
     758                 :     // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
     759                 :     // then something useful will be done with our request to debug.
     760               0 :     debugPossible = ((jsds_IsOn && (jsdHook != nsnull)) || !jsds_IsOn);
     761                 :   }
     762                 : #endif
     763                 : 
     764                 :   // Get localizable strings
     765               0 :   nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
     766                 : 
     767                 :   rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     768                 :                                           "KillScriptTitle",
     769               0 :                                           title);
     770                 : 
     771                 :   rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     772                 :                                            "StopScriptButton",
     773               0 :                                            stopButton);
     774                 : 
     775                 :   rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     776                 :                                            "WaitForScriptButton",
     777               0 :                                            waitButton);
     778                 : 
     779                 :   rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     780                 :                                            "DontAskAgain",
     781               0 :                                            neverShowDlg);
     782                 : 
     783                 : 
     784               0 :   if (debugPossible) {
     785                 :     rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     786                 :                                              "DebugScriptButton",
     787               0 :                                              debugButton);
     788                 : 
     789                 :     rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     790                 :                                              "KillScriptWithDebugMessage",
     791               0 :                                              msg);
     792                 :   }
     793                 :   else {
     794                 :     rv |= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     795                 :                                              "KillScriptMessage",
     796               0 :                                              msg);
     797                 :   }
     798                 : 
     799                 :   //GetStringFromName can return NS_OK and still give NULL string
     800               0 :   if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton ||
     801               0 :       (!debugButton && debugPossible) || !neverShowDlg) {
     802               0 :     NS_ERROR("Failed to get localized strings.");
     803               0 :     return JS_TRUE;
     804                 :   }
     805                 : 
     806                 :   // Append file and line number information, if available
     807               0 :   if (script) {
     808               0 :     const char *filename = ::JS_GetScriptFilename(cx, script);
     809               0 :     if (filename) {
     810               0 :       nsXPIDLString scriptLocation;
     811               0 :       NS_ConvertUTF8toUTF16 filenameUTF16(filename);
     812               0 :       const PRUnichar *formatParams[] = { filenameUTF16.get() };
     813                 :       rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     814                 :                                                  "KillScriptLocation",
     815                 :                                                  formatParams,
     816               0 :                                                  scriptLocation);
     817                 : 
     818               0 :       if (NS_SUCCEEDED(rv) && scriptLocation) {
     819               0 :         msg.AppendLiteral("\n\n");
     820               0 :         msg.Append(scriptLocation);
     821               0 :         msg.Append(':');
     822               0 :         msg.AppendInt(lineno);
     823                 :       }
     824                 :     }
     825                 :   }
     826                 : 
     827               0 :   PRInt32 buttonPressed = 0; //In case user exits dialog by clicking X
     828               0 :   bool neverShowDlgChk = false;
     829                 :   PRUint32 buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
     830                 :                          (nsIPrompt::BUTTON_TITLE_IS_STRING *
     831               0 :                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
     832                 : 
     833                 :   // Add a third button if necessary:
     834               0 :   if (debugPossible)
     835               0 :     buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
     836                 : 
     837                 :   // Null out the operation callback while we're re-entering JS here.
     838               0 :   ::JS_SetOperationCallback(cx, nsnull);
     839                 : 
     840                 :   // Open the dialog.
     841               0 :   rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
     842                 :                          debugButton, neverShowDlg, &neverShowDlgChk,
     843               0 :                          &buttonPressed);
     844                 : 
     845               0 :   ::JS_SetOperationCallback(cx, DOMOperationCallback);
     846                 : 
     847               0 :   if (NS_FAILED(rv) || (buttonPressed == 0)) {
     848                 :     // Allow the script to continue running
     849                 : 
     850               0 :     if (neverShowDlgChk) {
     851                 :       Preferences::SetInt(isTrackingChromeCodeTime ?
     852               0 :         "dom.max_chrome_script_run_time" : "dom.max_script_run_time", 0);
     853                 :     }
     854                 : 
     855               0 :     ctx->mOperationCallbackTime = PR_Now();
     856               0 :     return JS_TRUE;
     857                 :   }
     858               0 :   else if ((buttonPressed == 2) && debugPossible) {
     859               0 :     return js_CallContextDebugHandler(cx);
     860                 :   }
     861                 : 
     862               0 :   JS_ClearPendingException(cx);
     863               0 :   return JS_FALSE;
     864                 : }
     865                 : 
     866                 : void
     867               0 : nsJSContext::EnterModalState()
     868                 : {
     869               0 :   if (!mModalStateDepth) {
     870               0 :     mModalStateTime =  mOperationCallbackTime ? PR_Now() : 0;
     871                 :   }
     872               0 :   ++mModalStateDepth;
     873               0 : }
     874                 : 
     875                 : void
     876               0 : nsJSContext::LeaveModalState()
     877                 : {
     878               0 :   if (!mModalStateDepth) {
     879               0 :     NS_ERROR("Uh, mismatched LeaveModalState() call!");
     880                 : 
     881               0 :     return;
     882                 :   }
     883                 : 
     884               0 :   --mModalStateDepth;
     885                 : 
     886                 :   // If we're still in a modal dialog, or mOperationCallbackTime is still
     887                 :   // uninitialized, do nothing.
     888               0 :   if (mModalStateDepth || !mOperationCallbackTime) {
     889               0 :     return;
     890                 :   }
     891                 : 
     892                 :   // If mOperationCallbackTime was set when we entered the first dialog
     893                 :   // (and mModalStateTime is thus non-zero), adjust mOperationCallbackTime
     894                 :   // to account for time spent in the dialog.
     895                 :   // If mOperationCallbackTime got set while the modal dialog was open,
     896                 :   // simply set mOperationCallbackTime to the closing time of the dialog so
     897                 :   // that we never adjust mOperationCallbackTime to be in the future. 
     898               0 :   if (mModalStateTime) {
     899               0 :     mOperationCallbackTime += PR_Now() - mModalStateTime;
     900                 :   }
     901                 :   else {
     902               0 :     mOperationCallbackTime = PR_Now();
     903                 :   }
     904                 : }
     905                 : 
     906                 : #define JS_OPTIONS_DOT_STR "javascript.options."
     907                 : 
     908                 : static const char js_options_dot_str[]   = JS_OPTIONS_DOT_STR;
     909                 : static const char js_strict_option_str[] = JS_OPTIONS_DOT_STR "strict";
     910                 : #ifdef DEBUG
     911                 : static const char js_strict_debug_option_str[] = JS_OPTIONS_DOT_STR "strict.debug";
     912                 : #endif
     913                 : static const char js_werror_option_str[] = JS_OPTIONS_DOT_STR "werror";
     914                 : static const char js_relimit_option_str[]= JS_OPTIONS_DOT_STR "relimit";
     915                 : #ifdef JS_GC_ZEAL
     916                 : static const char js_zeal_option_str[]        = JS_OPTIONS_DOT_STR "gczeal";
     917                 : static const char js_zeal_frequency_str[]     = JS_OPTIONS_DOT_STR "gczeal.frequency";
     918                 : static const char js_zeal_compartment_str[]   = JS_OPTIONS_DOT_STR "gczeal.compartment_gc";
     919                 : #endif
     920                 : static const char js_methodjit_content_str[]  = JS_OPTIONS_DOT_STR "methodjit.content";
     921                 : static const char js_methodjit_chrome_str[]   = JS_OPTIONS_DOT_STR "methodjit.chrome";
     922                 : static const char js_methodjit_always_str[]   = JS_OPTIONS_DOT_STR "methodjit_always";
     923                 : static const char js_typeinfer_str[]          = JS_OPTIONS_DOT_STR "typeinference";
     924                 : static const char js_pccounts_content_str[]   = JS_OPTIONS_DOT_STR "pccounts.content";
     925                 : static const char js_pccounts_chrome_str[]    = JS_OPTIONS_DOT_STR "pccounts.chrome";
     926                 : static const char js_jit_hardening_str[]      = JS_OPTIONS_DOT_STR "jit_hardening";
     927                 : static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
     928                 : 
     929                 : int
     930               0 : nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
     931                 : {
     932               0 :   nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
     933               0 :   PRUint32 oldDefaultJSOptions = context->mDefaultJSOptions;
     934               0 :   PRUint32 newDefaultJSOptions = oldDefaultJSOptions;
     935                 : 
     936               0 :   sPostGCEventsToConsole = Preferences::GetBool(js_memlog_option_str);
     937                 : 
     938               0 :   bool strict = Preferences::GetBool(js_strict_option_str);
     939               0 :   if (strict)
     940               0 :     newDefaultJSOptions |= JSOPTION_STRICT;
     941                 :   else
     942               0 :     newDefaultJSOptions &= ~JSOPTION_STRICT;
     943                 : 
     944               0 :   nsIScriptGlobalObject *global = context->GetGlobalObject();
     945                 :   // XXX should we check for sysprin instead of a chrome window, to make
     946                 :   // XXX components be covered by the chrome pref instead of the content one?
     947               0 :   nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(global));
     948                 : 
     949                 :   bool useMethodJIT = Preferences::GetBool(chromeWindow ?
     950                 :                                                js_methodjit_chrome_str :
     951               0 :                                                js_methodjit_content_str);
     952                 :   bool usePCCounts = Preferences::GetBool(chromeWindow ?
     953                 :                                             js_pccounts_chrome_str :
     954               0 :                                             js_pccounts_content_str);
     955               0 :   bool useMethodJITAlways = Preferences::GetBool(js_methodjit_always_str);
     956               0 :   bool useTypeInference = !chromeWindow && Preferences::GetBool(js_typeinfer_str);
     957               0 :   bool useHardening = Preferences::GetBool(js_jit_hardening_str);
     958               0 :   nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
     959               0 :   if (xr) {
     960               0 :     bool safeMode = false;
     961               0 :     xr->GetInSafeMode(&safeMode);
     962               0 :     if (safeMode) {
     963               0 :       useMethodJIT = false;
     964               0 :       usePCCounts = false;
     965               0 :       useTypeInference = false;
     966               0 :       useMethodJITAlways = true;
     967               0 :       useHardening = false;
     968                 :     }
     969                 :   }    
     970                 : 
     971               0 :   if (useMethodJIT)
     972               0 :     newDefaultJSOptions |= JSOPTION_METHODJIT;
     973                 :   else
     974               0 :     newDefaultJSOptions &= ~JSOPTION_METHODJIT;
     975                 : 
     976               0 :   if (usePCCounts)
     977               0 :     newDefaultJSOptions |= JSOPTION_PCCOUNT;
     978                 :   else
     979               0 :     newDefaultJSOptions &= ~JSOPTION_PCCOUNT;
     980                 : 
     981               0 :   if (useMethodJITAlways)
     982               0 :     newDefaultJSOptions |= JSOPTION_METHODJIT_ALWAYS;
     983                 :   else
     984               0 :     newDefaultJSOptions &= ~JSOPTION_METHODJIT_ALWAYS;
     985                 : 
     986               0 :   if (useTypeInference)
     987               0 :     newDefaultJSOptions |= JSOPTION_TYPE_INFERENCE;
     988                 :   else
     989               0 :     newDefaultJSOptions &= ~JSOPTION_TYPE_INFERENCE;
     990                 : 
     991                 : #ifdef DEBUG
     992                 :   // In debug builds, warnings are enabled in chrome context if
     993                 :   // javascript.options.strict.debug is true
     994               0 :   bool strictDebug = Preferences::GetBool(js_strict_debug_option_str);
     995                 :   // Note this callback is also called from context's InitClasses thus we don't
     996                 :   // need to enable this directly from InitContext
     997               0 :   if (strictDebug && (newDefaultJSOptions & JSOPTION_STRICT) == 0) {
     998               0 :     if (chromeWindow)
     999               0 :       newDefaultJSOptions |= JSOPTION_STRICT;
    1000                 :   }
    1001                 : #endif
    1002                 : 
    1003               0 :   bool werror = Preferences::GetBool(js_werror_option_str);
    1004               0 :   if (werror)
    1005               0 :     newDefaultJSOptions |= JSOPTION_WERROR;
    1006                 :   else
    1007               0 :     newDefaultJSOptions &= ~JSOPTION_WERROR;
    1008                 : 
    1009               0 :   bool relimit = Preferences::GetBool(js_relimit_option_str);
    1010               0 :   if (relimit)
    1011               0 :     newDefaultJSOptions |= JSOPTION_RELIMIT;
    1012                 :   else
    1013               0 :     newDefaultJSOptions &= ~JSOPTION_RELIMIT;
    1014                 : 
    1015               0 :   ::JS_SetOptions(context->mContext, newDefaultJSOptions & JSRUNOPTION_MASK);
    1016                 : 
    1017                 :   // Save the new defaults for the next page load (InitContext).
    1018               0 :   context->mDefaultJSOptions = newDefaultJSOptions;
    1019                 : 
    1020               0 :   JSRuntime *rt = JS_GetRuntime(context->mContext);
    1021               0 :   JS_SetJitHardening(rt, useHardening);
    1022                 : 
    1023                 : #ifdef JS_GC_ZEAL
    1024               0 :   PRInt32 zeal = Preferences::GetInt(js_zeal_option_str, -1);
    1025               0 :   PRInt32 frequency = Preferences::GetInt(js_zeal_frequency_str, JS_DEFAULT_ZEAL_FREQ);
    1026               0 :   bool compartment = Preferences::GetBool(js_zeal_compartment_str, false);
    1027               0 :   if (zeal >= 0)
    1028               0 :     ::JS_SetGCZeal(context->mContext, (PRUint8)zeal, frequency, compartment);
    1029                 : #endif
    1030                 : 
    1031               0 :   return 0;
    1032                 : }
    1033                 : 
    1034               0 : nsJSContext::nsJSContext(JSRuntime *aRuntime)
    1035                 :   : mGCOnDestruction(true),
    1036               0 :     mExecuteDepth(0)
    1037                 : {
    1038                 : 
    1039               0 :   ++sContextCount;
    1040                 : 
    1041               0 :   mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS;
    1042                 : 
    1043               0 :   mContext = ::JS_NewContext(aRuntime, gStackSize);
    1044               0 :   if (mContext) {
    1045               0 :     ::JS_SetContextPrivate(mContext, static_cast<nsIScriptContext *>(this));
    1046                 : 
    1047                 :     // Preserve any flags the context callback might have set.
    1048               0 :     mDefaultJSOptions |= ::JS_GetOptions(mContext);
    1049                 : 
    1050                 :     // Make sure the new context gets the default context options
    1051               0 :     ::JS_SetOptions(mContext, mDefaultJSOptions);
    1052                 : 
    1053                 :     // Watch for the JS boolean options
    1054                 :     Preferences::RegisterCallback(JSOptionChangedCallback,
    1055               0 :                                   js_options_dot_str, this);
    1056                 : 
    1057               0 :     ::JS_SetOperationCallback(mContext, DOMOperationCallback);
    1058                 : 
    1059               0 :     xpc_LocalizeContext(mContext);
    1060                 :   }
    1061               0 :   mIsInitialized = false;
    1062               0 :   mTerminations = nsnull;
    1063               0 :   mScriptsEnabled = true;
    1064               0 :   mOperationCallbackTime = 0;
    1065               0 :   mModalStateTime = 0;
    1066               0 :   mModalStateDepth = 0;
    1067               0 :   mProcessingScriptTag = false;
    1068               0 : }
    1069                 : 
    1070               0 : nsJSContext::~nsJSContext()
    1071                 : {
    1072                 : #ifdef DEBUG
    1073               0 :   nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptContext*>(this));
    1074                 : #endif
    1075                 : 
    1076                 :   // We may still have pending termination functions if the context is destroyed
    1077                 :   // before they could be executed. In this case, free the references to their
    1078                 :   // parameters, but don't execute the functions (see bug 622326).
    1079               0 :   delete mTerminations;
    1080                 : 
    1081               0 :   mGlobalObjectRef = nsnull;
    1082                 : 
    1083               0 :   DestroyJSContext();
    1084                 : 
    1085               0 :   --sContextCount;
    1086                 : 
    1087               0 :   if (!sContextCount && sDidShutdown) {
    1088                 :     // The last context is being deleted, and we're already in the
    1089                 :     // process of shutting down, release the JS runtime service, and
    1090                 :     // the security manager.
    1091                 : 
    1092               0 :     NS_IF_RELEASE(sRuntimeService);
    1093               0 :     NS_IF_RELEASE(sSecurityManager);
    1094                 :   }
    1095               0 : }
    1096                 : 
    1097                 : void
    1098               0 : nsJSContext::DestroyJSContext()
    1099                 : {
    1100               0 :   if (!mContext) {
    1101               0 :     return;
    1102                 :   }
    1103                 : 
    1104                 :   // Clear our entry in the JSContext, bugzilla bug 66413
    1105               0 :   ::JS_SetContextPrivate(mContext, nsnull);
    1106                 : 
    1107                 :   // Unregister our "javascript.options.*" pref-changed callback.
    1108                 :   Preferences::UnregisterCallback(JSOptionChangedCallback,
    1109               0 :                                   js_options_dot_str, this);
    1110                 : 
    1111               0 :   if (mGCOnDestruction) {
    1112               0 :     PokeGC(js::gcreason::NSJSCONTEXT_DESTROY);
    1113                 :   }
    1114                 :         
    1115                 :   // Let xpconnect destroy the JSContext when it thinks the time is right.
    1116               0 :   nsIXPConnect *xpc = nsContentUtils::XPConnect();
    1117               0 :   if (xpc) {
    1118               0 :     xpc->ReleaseJSContext(mContext, true);
    1119                 :   } else {
    1120               0 :     ::JS_DestroyContextNoGC(mContext);
    1121                 :   }
    1122               0 :   mContext = nsnull;
    1123                 : }
    1124                 : 
    1125                 : // QueryInterface implementation for nsJSContext
    1126            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext)
    1127               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext)
    1128               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    1129               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext)
    1130               0 :   NS_ASSERTION(!tmp->mContext || js::GetContextOutstandingRequests(tmp->mContext) == 0,
    1131                 :                "Trying to unlink a context with outstanding requests.");
    1132               0 :   tmp->mIsInitialized = false;
    1133               0 :   tmp->mGCOnDestruction = false;
    1134               0 :   tmp->DestroyJSContext();
    1135               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObjectRef)
    1136               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1137               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext)
    1138               0 :   NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext, tmp->GetCCRefcnt())
    1139               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalObjectRef)
    1140               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContext");
    1141               0 :   nsContentUtils::XPConnect()->NoteJSContext(tmp->mContext, cb);
    1142               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1143                 : 
    1144               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext)
    1145               0 :   NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
    1146               0 :   NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal)
    1147               0 :   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify)
    1148               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptContext)
    1149               0 : NS_INTERFACE_MAP_END
    1150                 : 
    1151                 : 
    1152               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSContext)
    1153               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSContext)
    1154                 : 
    1155                 : nsrefcnt
    1156               0 : nsJSContext::GetCCRefcnt()
    1157                 : {
    1158               0 :   nsrefcnt refcnt = mRefCnt.get();
    1159               0 :   if (NS_LIKELY(mContext))
    1160               0 :     refcnt += js::GetContextOutstandingRequests(mContext);
    1161               0 :   return refcnt;
    1162                 : }
    1163                 : 
    1164                 : nsresult
    1165               0 : nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
    1166                 :                                      JSObject* aScopeObject,
    1167                 :                                      nsIPrincipal *aPrincipal,
    1168                 :                                      const char *aURL,
    1169                 :                                      PRUint32 aLineNo,
    1170                 :                                      PRUint32 aVersion,
    1171                 :                                      JS::Value* aRetValue,
    1172                 :                                      bool* aIsUndefined)
    1173                 : {
    1174                 :   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME,
    1175                 :                            __LINE__, aURL, aLineNo);
    1176                 : 
    1177               0 :   SAMPLE_LABEL("JS", "EvaluateStringWithValue");
    1178               0 :   NS_ABORT_IF_FALSE(aScopeObject,
    1179                 :     "Shouldn't call EvaluateStringWithValue with null scope object.");
    1180                 : 
    1181               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1182                 : 
    1183               0 :   if (!mScriptsEnabled) {
    1184               0 :     if (aIsUndefined) {
    1185               0 :       *aIsUndefined = true;
    1186                 :     }
    1187                 : 
    1188               0 :     return NS_OK;
    1189                 :   }
    1190                 : 
    1191                 :   // Safety first: get an object representing the script's principals, i.e.,
    1192                 :   // the entities who signed this script, or the fully-qualified-domain-name
    1193                 :   // or "codebase" from which it was loaded.
    1194               0 :   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
    1195                 :   nsresult rv;
    1196               0 :   if (!aPrincipal) {
    1197               0 :     nsIScriptGlobalObject *global = GetGlobalObject();
    1198               0 :     if (!global)
    1199               0 :       return NS_ERROR_FAILURE;
    1200                 :     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
    1201               0 :       do_QueryInterface(global, &rv);
    1202               0 :     if (NS_FAILED(rv))
    1203               0 :       return NS_ERROR_FAILURE;
    1204               0 :     principal = objPrincipal->GetPrincipal();
    1205               0 :     if (!principal)
    1206               0 :       return NS_ERROR_FAILURE;
    1207                 :   }
    1208                 : 
    1209               0 :   bool ok = false;
    1210                 : 
    1211               0 :   rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
    1212               0 :   if (NS_FAILED(rv)) {
    1213               0 :     return NS_ERROR_FAILURE;
    1214                 :   }
    1215                 : 
    1216                 :   // Push our JSContext on the current thread's context stack so JS called
    1217                 :   // from native code via XPConnect uses the right context.  Do this whether
    1218                 :   // or not the SecurityManager said "ok", in order to simplify control flow
    1219                 :   // below where we pop before returning.
    1220                 :   nsCOMPtr<nsIJSContextStack> stack =
    1221               0 :            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
    1222               0 :   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
    1223               0 :     return NS_ERROR_FAILURE;
    1224                 :   }
    1225                 : 
    1226                 :   jsval val;
    1227                 : 
    1228               0 :   rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
    1229               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1230                 : 
    1231               0 :   nsJSContext::TerminationFuncHolder holder(this);
    1232                 : 
    1233                 :   // SecurityManager said "ok", but don't compile if aVersion is unknown.
    1234                 :   // Since the caller is responsible for parsing the version strings, we just
    1235                 :   // check it isn't JSVERSION_UNKNOWN.
    1236               0 :   if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
    1237                 : 
    1238               0 :     JSAutoRequest ar(mContext);
    1239                 : 
    1240               0 :     JSAutoEnterCompartment ac;
    1241               0 :     if (!ac.enter(mContext, aScopeObject)) {
    1242               0 :       stack->Pop(nsnull);
    1243               0 :       return NS_ERROR_FAILURE;
    1244                 :     }
    1245                 : 
    1246               0 :     ++mExecuteDepth;
    1247                 : 
    1248                 :     ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
    1249                 :                                                    aScopeObject,
    1250               0 :                                                    nsJSPrincipals::get(principal),
    1251               0 :                                                    static_cast<const jschar*>(PromiseFlatString(aScript).get()),
    1252                 :                                                    aScript.Length(),
    1253                 :                                                    aURL,
    1254                 :                                                    aLineNo,
    1255                 :                                                    &val,
    1256               0 :                                                    JSVersion(aVersion));
    1257                 : 
    1258               0 :     --mExecuteDepth;
    1259                 : 
    1260               0 :     if (!ok) {
    1261                 :       // Tell XPConnect about any pending exceptions. This is needed
    1262                 :       // to avoid dropping JS exceptions in case we got here through
    1263                 :       // nested calls through XPConnect.
    1264                 : 
    1265               0 :       ReportPendingException();
    1266                 :     }
    1267                 :   }
    1268                 : 
    1269                 :   // If all went well, convert val to a string (XXXbe unless undefined?).
    1270               0 :   if (ok) {
    1271               0 :     if (aIsUndefined) {
    1272               0 :       *aIsUndefined = JSVAL_IS_VOID(val);
    1273                 :     }
    1274                 : 
    1275               0 :     *aRetValue = val;
    1276                 :     // XXX - nsScriptObjectHolder should be used once this method moves to
    1277                 :     // the new world order. However, use of 'jsval' appears to make this
    1278                 :     // tricky...
    1279                 :   }
    1280                 :   else {
    1281               0 :     if (aIsUndefined) {
    1282               0 :       *aIsUndefined = true;
    1283                 :     }
    1284                 :   }
    1285                 : 
    1286               0 :   sSecurityManager->PopContextPrincipal(mContext);
    1287                 : 
    1288                 :   // Pop here, after JS_ValueToString and any other possible evaluation.
    1289               0 :   if (NS_FAILED(stack->Pop(nsnull)))
    1290               0 :     rv = NS_ERROR_FAILURE;
    1291                 : 
    1292                 :   // ScriptEvaluated needs to come after we pop the stack
    1293               0 :   ScriptEvaluated(true);
    1294                 : 
    1295               0 :   return rv;
    1296                 : 
    1297                 : }
    1298                 : 
    1299                 : // Helper function to convert a jsval to an nsAString, and set
    1300                 : // exception flags if the conversion fails.
    1301                 : static nsresult
    1302               0 : JSValueToAString(JSContext *cx, jsval val, nsAString *result,
    1303                 :                  bool *isUndefined)
    1304                 : {
    1305               0 :   if (isUndefined) {
    1306               0 :     *isUndefined = JSVAL_IS_VOID(val);
    1307                 :   }
    1308                 : 
    1309               0 :   if (!result) {
    1310               0 :     return NS_OK;
    1311                 :   }
    1312                 : 
    1313               0 :   JSString* jsstring = ::JS_ValueToString(cx, val);
    1314               0 :   if (!jsstring) {
    1315               0 :     goto error;
    1316                 :   }
    1317                 : 
    1318                 :   size_t length;
    1319                 :   const jschar *chars;
    1320               0 :   chars = ::JS_GetStringCharsAndLength(cx, jsstring, &length);
    1321               0 :   if (!chars) {
    1322               0 :     goto error;
    1323                 :   }
    1324                 : 
    1325               0 :   result->Assign(chars, length);
    1326               0 :   return NS_OK;
    1327                 : 
    1328                 : error:
    1329                 :   // We failed to convert val to a string. We're either OOM, or the
    1330                 :   // security manager denied access to .toString(), or somesuch, on
    1331                 :   // an object. Treat this case as if the result were undefined.
    1332                 : 
    1333               0 :   result->Truncate();
    1334                 : 
    1335               0 :   if (isUndefined) {
    1336               0 :     *isUndefined = true;
    1337                 :   }
    1338                 : 
    1339               0 :   if (!::JS_IsExceptionPending(cx)) {
    1340                 :     // JS_ValueToString()/JS_GetStringCharsAndLength returned null w/o an
    1341                 :     // exception pending. That means we're OOM.
    1342                 : 
    1343               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1344                 :   }
    1345                 : 
    1346               0 :   return NS_OK;
    1347                 : }
    1348                 : 
    1349                 : nsIScriptObjectPrincipal*
    1350               0 : nsJSContext::GetObjectPrincipal()
    1351                 : {
    1352               0 :   nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(GetGlobalObject());
    1353               0 :   return prin;
    1354                 : }
    1355                 : 
    1356                 : nsresult
    1357               0 : nsJSContext::EvaluateString(const nsAString& aScript,
    1358                 :                             JSObject* aScopeObject,
    1359                 :                             nsIPrincipal *aPrincipal,
    1360                 :                             nsIPrincipal *aOriginPrincipal,
    1361                 :                             const char *aURL,
    1362                 :                             PRUint32 aLineNo,
    1363                 :                             PRUint32 aVersion,
    1364                 :                             nsAString *aRetValue,
    1365                 :                             bool* aIsUndefined)
    1366                 : {
    1367                 :   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME,
    1368                 :                            __LINE__, aURL, aLineNo);
    1369                 : 
    1370               0 :   SAMPLE_LABEL("JS", "EvaluateString");
    1371               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1372                 : 
    1373               0 :   if (!mScriptsEnabled) {
    1374               0 :     if (aIsUndefined) {
    1375               0 :       *aIsUndefined = true;
    1376                 :     }
    1377                 : 
    1378               0 :     if (aRetValue) {
    1379               0 :       aRetValue->Truncate();
    1380                 :     }
    1381                 : 
    1382               0 :     return NS_OK;
    1383                 :   }
    1384                 : 
    1385               0 :   if (!aScopeObject) {
    1386               0 :     aScopeObject = JS_GetGlobalObject(mContext);
    1387                 :   }
    1388                 : 
    1389                 :   // Safety first: get an object representing the script's principals, i.e.,
    1390                 :   // the entities who signed this script, or the fully-qualified-domain-name
    1391                 :   // or "codebase" from which it was loaded.
    1392               0 :   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
    1393               0 :   if (!aPrincipal) {
    1394                 :     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
    1395               0 :       do_QueryInterface(GetGlobalObject());
    1396               0 :     if (!objPrincipal)
    1397               0 :       return NS_ERROR_FAILURE;
    1398               0 :     principal = objPrincipal->GetPrincipal();
    1399               0 :     if (!principal)
    1400               0 :       return NS_ERROR_FAILURE;
    1401                 :   }
    1402                 : 
    1403               0 :   bool ok = false;
    1404                 : 
    1405               0 :   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
    1406               0 :   if (NS_FAILED(rv)) {
    1407               0 :     return NS_ERROR_FAILURE;
    1408                 :   }
    1409                 : 
    1410                 :   // Push our JSContext on the current thread's context stack so JS called
    1411                 :   // from native code via XPConnect uses the right context.  Do this whether
    1412                 :   // or not the SecurityManager said "ok", in order to simplify control flow
    1413                 :   // below where we pop before returning.
    1414                 :   nsCOMPtr<nsIJSContextStack> stack =
    1415               0 :            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
    1416               0 :   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
    1417               0 :     return NS_ERROR_FAILURE;
    1418                 :   }
    1419                 : 
    1420                 :   // The result of evaluation, used only if there were no errors.  This need
    1421                 :   // not be a GC root currently, provided we run the GC only from the
    1422                 :   // operation callback or from ScriptEvaluated.
    1423               0 :   jsval val = JSVAL_VOID;
    1424               0 :   jsval* vp = aRetValue ? &val : NULL;
    1425                 : 
    1426               0 :   rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
    1427               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1428                 : 
    1429               0 :   nsJSContext::TerminationFuncHolder holder(this);
    1430                 : 
    1431               0 :   ++mExecuteDepth;
    1432                 : 
    1433                 :   // SecurityManager said "ok", but don't compile if aVersion is unknown.
    1434                 :   // Since the caller is responsible for parsing the version strings, we just
    1435                 :   // check it isn't JSVERSION_UNKNOWN.
    1436               0 :   if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) {
    1437               0 :     JSAutoRequest ar(mContext);
    1438               0 :     JSAutoEnterCompartment ac;
    1439               0 :     if (!ac.enter(mContext, aScopeObject)) {
    1440               0 :       stack->Pop(nsnull);
    1441               0 :       return NS_ERROR_FAILURE;
    1442                 :     }
    1443                 : 
    1444                 :     ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(
    1445                 :       mContext, aScopeObject,
    1446               0 :       nsJSPrincipals::get(principal), nsJSPrincipals::get(aOriginPrincipal),
    1447               0 :       static_cast<const jschar*>(PromiseFlatString(aScript).get()),
    1448               0 :       aScript.Length(), aURL, aLineNo, vp, JSVersion(aVersion));
    1449                 : 
    1450               0 :     if (!ok) {
    1451                 :       // Tell XPConnect about any pending exceptions. This is needed
    1452                 :       // to avoid dropping JS exceptions in case we got here through
    1453                 :       // nested calls through XPConnect.
    1454                 : 
    1455               0 :       ReportPendingException();
    1456                 :     }
    1457                 :   }
    1458                 : 
    1459                 :   // If all went well, convert val to a string if one is wanted.
    1460               0 :   if (ok) {
    1461               0 :     JSAutoRequest ar(mContext);
    1462               0 :     JSAutoEnterCompartment ac;
    1463               0 :     if (!ac.enter(mContext, aScopeObject)) {
    1464               0 :       stack->Pop(nsnull);
    1465                 :     }
    1466               0 :     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
    1467                 :   }
    1468                 :   else {
    1469               0 :     if (aIsUndefined) {
    1470               0 :       *aIsUndefined = true;
    1471                 :     }
    1472                 : 
    1473               0 :     if (aRetValue) {
    1474               0 :       aRetValue->Truncate();
    1475                 :     }
    1476                 :   }
    1477                 : 
    1478               0 :   --mExecuteDepth;
    1479                 : 
    1480               0 :   sSecurityManager->PopContextPrincipal(mContext);
    1481                 : 
    1482                 :   // Pop here, after JS_ValueToString and any other possible evaluation.
    1483               0 :   if (NS_FAILED(stack->Pop(nsnull)))
    1484               0 :     rv = NS_ERROR_FAILURE;
    1485                 : 
    1486                 :   // ScriptEvaluated needs to come after we pop the stack
    1487               0 :   ScriptEvaluated(true);
    1488                 : 
    1489               0 :   return rv;
    1490                 : }
    1491                 : 
    1492                 : nsresult
    1493               0 : nsJSContext::CompileScript(const PRUnichar* aText,
    1494                 :                            PRInt32 aTextLength,
    1495                 :                            nsIPrincipal *aPrincipal,
    1496                 :                            const char *aURL,
    1497                 :                            PRUint32 aLineNo,
    1498                 :                            PRUint32 aVersion,
    1499                 :                            nsScriptObjectHolder<JSScript>& aScriptObject)
    1500                 : {
    1501               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1502                 : 
    1503               0 :   NS_ENSURE_ARG_POINTER(aPrincipal);
    1504                 : 
    1505               0 :   JSObject* scopeObject = ::JS_GetGlobalObject(mContext);
    1506                 : 
    1507               0 :   bool ok = false;
    1508                 : 
    1509               0 :   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, aPrincipal, &ok);
    1510               0 :   if (NS_FAILED(rv)) {
    1511               0 :     return NS_ERROR_FAILURE;
    1512                 :   }
    1513                 : 
    1514               0 :   aScriptObject.drop(); // ensure old object not used on failure...
    1515                 : 
    1516                 :   // Don't compile if SecurityManager said "not ok" or aVersion is unknown.
    1517                 :   // Since the caller is responsible for parsing the version strings, we just
    1518                 :   // check it isn't JSVERSION_UNKNOWN.
    1519               0 :   if (!ok || JSVersion(aVersion) == JSVERSION_UNKNOWN)
    1520               0 :     return NS_OK;
    1521                 :     
    1522               0 :   JSAutoRequest ar(mContext);
    1523                 : 
    1524                 :   JSScript* script =
    1525                 :     ::JS_CompileUCScriptForPrincipalsVersion(mContext,
    1526                 :                                              scopeObject,
    1527               0 :                                              nsJSPrincipals::get(aPrincipal),
    1528                 :                                              static_cast<const jschar*>(aText),
    1529                 :                                              aTextLength,
    1530                 :                                              aURL,
    1531                 :                                              aLineNo,
    1532               0 :                                              JSVersion(aVersion));
    1533               0 :   if (!script) {
    1534               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1535                 :   }
    1536               0 :   NS_ASSERTION(aScriptObject.getScriptTypeID()==JAVASCRIPT,
    1537                 :                "Expecting JS script object holder");
    1538               0 :   return aScriptObject.set(script);
    1539                 : }
    1540                 : 
    1541                 : nsresult
    1542               0 : nsJSContext::ExecuteScript(JSScript* aScriptObject,
    1543                 :                            JSObject* aScopeObject,
    1544                 :                            nsAString* aRetValue,
    1545                 :                            bool* aIsUndefined)
    1546                 : {
    1547               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1548                 : 
    1549               0 :   if (!mScriptsEnabled) {
    1550               0 :     if (aIsUndefined) {
    1551               0 :       *aIsUndefined = true;
    1552                 :     }
    1553                 : 
    1554               0 :     if (aRetValue) {
    1555               0 :       aRetValue->Truncate();
    1556                 :     }
    1557                 : 
    1558               0 :     return NS_OK;
    1559                 :   }
    1560                 : 
    1561               0 :   if (!aScopeObject) {
    1562               0 :     aScopeObject = JS_GetGlobalObject(mContext);
    1563                 :   }
    1564                 : 
    1565                 :   // Push our JSContext on our thread's context stack, in case native code
    1566                 :   // called from JS calls back into JS via XPConnect.
    1567                 :   nsresult rv;
    1568                 :   nsCOMPtr<nsIJSContextStack> stack =
    1569               0 :            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
    1570               0 :   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
    1571               0 :     return NS_ERROR_FAILURE;
    1572                 :   }
    1573                 : 
    1574               0 :   nsCOMPtr<nsIPrincipal> principal;
    1575                 :   rv = sSecurityManager->GetObjectPrincipal(mContext,
    1576                 :                                             JS_GetGlobalFromScript(aScriptObject),
    1577               0 :                                             getter_AddRefs(principal));
    1578               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1579                 : 
    1580               0 :   rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
    1581               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1582                 : 
    1583               0 :   nsJSContext::TerminationFuncHolder holder(this);
    1584               0 :   JSAutoRequest ar(mContext);
    1585               0 :   ++mExecuteDepth;
    1586                 : 
    1587                 :   // The result of evaluation, used only if there were no errors. This need
    1588                 :   // not be a GC root currently, provided we run the GC only from the
    1589                 :   // operation callback or from ScriptEvaluated.
    1590                 :   jsval val;
    1591               0 :   bool ok = JS_ExecuteScript(mContext, aScopeObject, aScriptObject, &val);
    1592               0 :   if (ok) {
    1593                 :     // If all went well, convert val to a string (XXXbe unless undefined?).
    1594               0 :     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
    1595                 :   } else {
    1596               0 :     ReportPendingException();
    1597                 : 
    1598               0 :     if (aIsUndefined) {
    1599               0 :       *aIsUndefined = true;
    1600                 :     }
    1601                 : 
    1602               0 :     if (aRetValue) {
    1603               0 :       aRetValue->Truncate();
    1604                 :     }
    1605                 :   }
    1606                 : 
    1607               0 :   --mExecuteDepth;
    1608                 : 
    1609               0 :   sSecurityManager->PopContextPrincipal(mContext);
    1610                 : 
    1611                 :   // Pop here, after JS_ValueToString and any other possible evaluation.
    1612               0 :   if (NS_FAILED(stack->Pop(nsnull)))
    1613               0 :     rv = NS_ERROR_FAILURE;
    1614                 : 
    1615                 :   // ScriptEvaluated needs to come after we pop the stack
    1616               0 :   ScriptEvaluated(true);
    1617                 : 
    1618               0 :   return rv;
    1619                 : }
    1620                 : 
    1621                 : 
    1622                 : #ifdef DEBUG
    1623                 : bool
    1624               0 : AtomIsEventHandlerName(nsIAtom *aName)
    1625                 : {
    1626               0 :   const PRUnichar *name = aName->GetUTF16String();
    1627                 : 
    1628                 :   const PRUnichar *cp;
    1629                 :   PRUnichar c;
    1630               0 :   for (cp = name; *cp != '\0'; ++cp)
    1631                 :   {
    1632               0 :     c = *cp;
    1633               0 :     if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z'))
    1634               0 :       return false;
    1635                 :   }
    1636                 : 
    1637               0 :   return true;
    1638                 : }
    1639                 : #endif
    1640                 : 
    1641                 : // Helper function to find the JSObject associated with a (presumably DOM)
    1642                 : // interface.
    1643                 : nsresult
    1644               0 : nsJSContext::JSObjectFromInterface(nsISupports* aTarget, JSObject* aScope, JSObject** aRet)
    1645                 : {
    1646                 :   // It is legal to specify a null target.
    1647               0 :   if (!aTarget) {
    1648               0 :     *aRet = nsnull;
    1649               0 :     return NS_OK;
    1650                 :   }
    1651                 : 
    1652                 :   // Get the jsobject associated with this target
    1653                 :   // We don't wrap here because we trust the JS engine to wrap the target
    1654                 :   // later.
    1655                 :   jsval v;
    1656               0 :   nsresult rv = nsContentUtils::WrapNative(mContext, aScope, aTarget, &v);
    1657               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1658                 : 
    1659                 : #ifdef NS_DEBUG
    1660               0 :   nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
    1661                 :   nsCOMPtr<nsISupports> native =
    1662               0 :     nsContentUtils::XPConnect()->GetNativeOfWrapper(mContext,
    1663               0 :                                                     JSVAL_TO_OBJECT(v));
    1664               0 :   NS_ASSERTION(native == targetSupp, "Native should be the target!");
    1665                 : #endif
    1666                 : 
    1667               0 :   *aRet = JSVAL_TO_OBJECT(v);
    1668                 : 
    1669               0 :   return NS_OK;
    1670                 : }
    1671                 : 
    1672                 : 
    1673                 : nsresult
    1674               0 : nsJSContext::CompileEventHandler(nsIAtom *aName,
    1675                 :                                  PRUint32 aArgCount,
    1676                 :                                  const char** aArgNames,
    1677                 :                                  const nsAString& aBody,
    1678                 :                                  const char *aURL, PRUint32 aLineNo,
    1679                 :                                  PRUint32 aVersion,
    1680                 :                                  nsScriptObjectHolder<JSObject>& aHandler)
    1681                 : {
    1682                 :   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME,
    1683                 :                            __LINE__, aURL, aLineNo);
    1684                 : 
    1685               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1686                 : 
    1687               0 :   NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
    1688               0 :   NS_PRECONDITION(!::JS_IsExceptionPending(mContext),
    1689                 :                   "Why are we being called with a pending exception?");
    1690                 : 
    1691               0 :   if (!sSecurityManager) {
    1692                 :     NS_ERROR("Huh, we need a script security manager to compile "
    1693               0 :              "an event handler!");
    1694                 : 
    1695               0 :     return NS_ERROR_UNEXPECTED;
    1696                 :   }
    1697                 : 
    1698                 :   // Don't compile if aVersion is unknown.  Since the caller is responsible for
    1699                 :   // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
    1700               0 :   if ((JSVersion)aVersion == JSVERSION_UNKNOWN) {
    1701               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1702                 :   }
    1703                 : 
    1704                 : #ifdef DEBUG
    1705               0 :   JSContext* top = nsContentUtils::GetCurrentJSContext();
    1706               0 :   NS_ASSERTION(mContext == top, "Context not properly pushed!");
    1707                 : #endif
    1708                 : 
    1709                 :   // Event handlers are always shared, and must be bound before use.
    1710                 :   // Therefore we never bother compiling with principals.
    1711                 :   // (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
    1712               0 :   JSAutoRequest ar(mContext);
    1713                 : 
    1714                 :   JSFunction* fun =
    1715                 :       ::JS_CompileUCFunctionForPrincipalsVersion(mContext,
    1716                 :                                                  nsnull, nsnull,
    1717               0 :                                                  nsAtomCString(aName).get(), aArgCount, aArgNames,
    1718               0 :                                                  (jschar*)PromiseFlatString(aBody).get(),
    1719                 :                                                  aBody.Length(),
    1720               0 :                                                  aURL, aLineNo, JSVersion(aVersion));
    1721                 : 
    1722               0 :   if (!fun) {
    1723               0 :     ReportPendingException();
    1724               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1725                 :   }
    1726                 : 
    1727               0 :   JSObject *handler = ::JS_GetFunctionObject(fun);
    1728               0 :   NS_ASSERTION(aHandler.getScriptTypeID()==JAVASCRIPT,
    1729                 :                "Expecting JS script object holder");
    1730               0 :   return aHandler.set(handler);
    1731                 : }
    1732                 : 
    1733                 : // XXX - note that CompileFunction doesn't yet play the nsScriptObjectHolder
    1734                 : // game - caller must still ensure JS GC root.
    1735                 : nsresult
    1736               0 : nsJSContext::CompileFunction(JSObject* aTarget,
    1737                 :                              const nsACString& aName,
    1738                 :                              PRUint32 aArgCount,
    1739                 :                              const char** aArgArray,
    1740                 :                              const nsAString& aBody,
    1741                 :                              const char* aURL,
    1742                 :                              PRUint32 aLineNo,
    1743                 :                              PRUint32 aVersion,
    1744                 :                              bool aShared,
    1745                 :                              JSObject** aFunctionObject)
    1746                 : {
    1747                 :   NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s, url: %s, line: %d)", MOZ_FUNCTION_NAME,
    1748                 :                        __LINE__, aName.BeginReading(), aURL, aLineNo);
    1749                 : 
    1750               0 :   NS_ABORT_IF_FALSE(aFunctionObject,
    1751                 :     "Shouldn't call CompileFunction with null return value.");
    1752                 : 
    1753               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1754                 : 
    1755                 :   // Don't compile if aVersion is unknown.  Since the caller is responsible for
    1756                 :   // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
    1757               0 :   if ((JSVersion)aVersion == JSVERSION_UNKNOWN) {
    1758               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1759                 :   }
    1760                 : 
    1761               0 :   nsIScriptGlobalObject *global = GetGlobalObject();
    1762               0 :   nsCOMPtr<nsIPrincipal> principal;
    1763               0 :   if (global) {
    1764                 :     // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
    1765               0 :     nsCOMPtr<nsIScriptObjectPrincipal> globalData = do_QueryInterface(global);
    1766               0 :     if (globalData) {
    1767               0 :       principal = globalData->GetPrincipal();
    1768               0 :       if (!principal)
    1769               0 :         return NS_ERROR_FAILURE;
    1770                 :     }
    1771                 :   }
    1772                 : 
    1773               0 :   JSObject *target = aTarget;
    1774                 : 
    1775               0 :   JSAutoRequest ar(mContext);
    1776                 : 
    1777                 :   JSFunction* fun =
    1778                 :       ::JS_CompileUCFunctionForPrincipalsVersion(mContext,
    1779                 :                                                  aShared ? nsnull : target,
    1780               0 :                                                  nsJSPrincipals::get(principal),
    1781               0 :                                                  PromiseFlatCString(aName).get(),
    1782                 :                                                  aArgCount, aArgArray,
    1783               0 :                                                  static_cast<const jschar*>(PromiseFlatString(aBody).get()),
    1784                 :                                                  aBody.Length(),
    1785                 :                                                  aURL, aLineNo,
    1786               0 :                                                  JSVersion(aVersion));
    1787                 : 
    1788               0 :   if (!fun)
    1789               0 :     return NS_ERROR_FAILURE;
    1790                 : 
    1791               0 :   *aFunctionObject = JS_GetFunctionObject(fun);
    1792               0 :   return NS_OK;
    1793                 : }
    1794                 : 
    1795                 : nsresult
    1796               0 : nsJSContext::CallEventHandler(nsISupports* aTarget, JSObject* aScope,
    1797                 :                               JSObject* aHandler, nsIArray* aargv,
    1798                 :                               nsIVariant** arv)
    1799                 : {
    1800               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1801                 : 
    1802               0 :   if (!mScriptsEnabled) {
    1803               0 :     return NS_OK;
    1804                 :   }
    1805                 : 
    1806                 : #ifdef NS_FUNCTION_TIMER
    1807                 :   {
    1808                 :     JSObject *obj = aHandler;
    1809                 :     if (js::IsFunctionProxy(obj))
    1810                 :       obj = js::UnwrapObject(obj);
    1811                 :     JSString *id = JS_GetFunctionId(static_cast<JSFunction *>(JS_GetPrivate(obj)));
    1812                 :     JSAutoByteString bytes;
    1813                 :     const char *name = !id ? "anonymous" : bytes.encode(mContext, id) ? bytes.ptr() : "<error>";
    1814                 :     NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME, __LINE__, name);
    1815                 :   }
    1816                 : #endif
    1817               0 :   SAMPLE_LABEL("JS", "CallEventHandler");
    1818                 : 
    1819               0 :   JSAutoRequest ar(mContext);
    1820               0 :   JSObject* target = nsnull;
    1821               0 :   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
    1822               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1823                 : 
    1824               0 :   JS::AutoObjectRooter targetVal(mContext, target);
    1825               0 :   jsval rval = JSVAL_VOID;
    1826                 : 
    1827                 :   // This one's a lot easier than EvaluateString because we don't have to
    1828                 :   // hassle with principals: they're already compiled into the JS function.
    1829                 :   // xxxmarkh - this comment is no longer true - principals are not used at
    1830                 :   // all now, and never were in some cases.
    1831                 : 
    1832               0 :   nsCxPusher pusher;
    1833               0 :   if (!pusher.Push(mContext, true))
    1834               0 :     return NS_ERROR_FAILURE;
    1835                 : 
    1836                 :   // check if the event handler can be run on the object in question
    1837               0 :   rv = sSecurityManager->CheckFunctionAccess(mContext, aHandler, target);
    1838                 : 
    1839               0 :   nsJSContext::TerminationFuncHolder holder(this);
    1840                 : 
    1841               0 :   if (NS_SUCCEEDED(rv)) {
    1842                 :     // Convert args to jsvals.
    1843               0 :     PRUint32 argc = 0;
    1844               0 :     jsval *argv = nsnull;
    1845                 : 
    1846               0 :     JSObject *funobj = aHandler;
    1847               0 :     nsCOMPtr<nsIPrincipal> principal;
    1848                 :     rv = sSecurityManager->GetObjectPrincipal(mContext, funobj,
    1849               0 :                                               getter_AddRefs(principal));
    1850               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1851                 : 
    1852               0 :     JSStackFrame *currentfp = nsnull;
    1853                 :     rv = sSecurityManager->PushContextPrincipal(mContext,
    1854                 :                                                 JS_FrameIterator(mContext, &currentfp),
    1855               0 :                                                 principal);
    1856               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1857                 : 
    1858               0 :     jsval funval = OBJECT_TO_JSVAL(funobj);
    1859               0 :     JSAutoEnterCompartment ac;
    1860               0 :     js::ForceFrame ff(mContext, funobj);
    1861               0 :     if (!ac.enter(mContext, funobj) || !ff.enter() ||
    1862               0 :         !JS_WrapObject(mContext, &target)) {
    1863               0 :       ReportPendingException();
    1864               0 :       sSecurityManager->PopContextPrincipal(mContext);
    1865               0 :       return NS_ERROR_FAILURE;
    1866                 :     }
    1867                 : 
    1868               0 :     Maybe<nsRootedJSValueArray> tempStorage;
    1869                 : 
    1870                 :     // Use |target| as the scope for wrapping the arguments, since aScope is
    1871                 :     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
    1872                 :     // was OK because those typically have PreCreate methods that give them the
    1873                 :     // right scope anyway, and we want to make sure that the arguments end up
    1874                 :     // in the same scope as aTarget.
    1875               0 :     rv = ConvertSupportsTojsvals(aargv, target, &argc, &argv, tempStorage);
    1876               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1877                 : 
    1878               0 :     ++mExecuteDepth;
    1879                 :     bool ok = ::JS_CallFunctionValue(mContext, target,
    1880               0 :                                        funval, argc, argv, &rval);
    1881               0 :     --mExecuteDepth;
    1882                 : 
    1883               0 :     if (!ok) {
    1884                 :       // Don't pass back results from failed calls.
    1885               0 :       rval = JSVAL_VOID;
    1886                 : 
    1887                 :       // Tell the caller that the handler threw an error.
    1888               0 :       rv = NS_ERROR_FAILURE;
    1889               0 :     } else if (rval == JSVAL_NULL) {
    1890               0 :       *arv = nsnull;
    1891               0 :     } else if (!JS_WrapValue(mContext, &rval)) {
    1892               0 :       rv = NS_ERROR_FAILURE;
    1893                 :     } else {
    1894               0 :       rv = nsContentUtils::XPConnect()->JSToVariant(mContext, rval, arv);
    1895                 :     }
    1896                 : 
    1897                 :     // Tell XPConnect about any pending exceptions. This is needed
    1898                 :     // to avoid dropping JS exceptions in case we got here through
    1899                 :     // nested calls through XPConnect.
    1900               0 :     if (NS_FAILED(rv))
    1901               0 :       ReportPendingException();
    1902                 : 
    1903               0 :     sSecurityManager->PopContextPrincipal(mContext);
    1904                 :   }
    1905                 : 
    1906               0 :   pusher.Pop();
    1907                 : 
    1908                 :   // ScriptEvaluated needs to come after we pop the stack
    1909               0 :   ScriptEvaluated(true);
    1910                 : 
    1911               0 :   return rv;
    1912                 : }
    1913                 : 
    1914                 : nsresult
    1915               0 : nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, JSObject* aScope,
    1916                 :                                       JSObject* aHandler,
    1917                 :                                       nsScriptObjectHolder<JSObject>& aBoundHandler)
    1918                 : {
    1919               0 :   NS_ENSURE_ARG(aHandler);
    1920               0 :   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
    1921               0 :   NS_PRECONDITION(!aBoundHandler, "Shouldn't already have a bound handler!");
    1922                 : 
    1923               0 :   JSAutoRequest ar(mContext);
    1924                 : 
    1925                 :   // Get the jsobject associated with this target
    1926               0 :   JSObject *target = nsnull;
    1927               0 :   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
    1928               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1929                 : 
    1930                 : #ifdef DEBUG
    1931                 :   {
    1932               0 :     JSAutoEnterCompartment ac;
    1933               0 :     if (!ac.enter(mContext, aHandler)) {
    1934               0 :       return NS_ERROR_FAILURE;
    1935                 :     }
    1936                 : 
    1937               0 :     NS_ASSERTION(JS_TypeOfValue(mContext,
    1938                 :                                 OBJECT_TO_JSVAL(aHandler)) == JSTYPE_FUNCTION,
    1939                 :                  "Event handler object not a function");
    1940                 :   }
    1941                 : #endif
    1942                 : 
    1943               0 :   JSAutoEnterCompartment ac;
    1944               0 :   if (!ac.enter(mContext, target)) {
    1945               0 :     return NS_ERROR_FAILURE;
    1946                 :   }
    1947                 : 
    1948                 :   JSObject* funobj;
    1949                 :   // Make sure the handler function is parented by its event target object
    1950               0 :   if (aHandler) {
    1951               0 :     funobj = JS_CloneFunctionObject(mContext, aHandler, target);
    1952               0 :     if (!funobj) {
    1953               0 :       rv = NS_ERROR_OUT_OF_MEMORY;
    1954                 :     }
    1955                 :   } else {
    1956               0 :     funobj = NULL;
    1957                 :   }
    1958                 : 
    1959               0 :   aBoundHandler.set(funobj);
    1960                 : 
    1961               0 :   return rv;
    1962                 : }
    1963                 : 
    1964                 : // serialization
    1965                 : nsresult
    1966               0 : nsJSContext::Serialize(nsIObjectOutputStream* aStream, JSScript* aScriptObject)
    1967                 : {
    1968               0 :     if (!aScriptObject)
    1969               0 :         return NS_ERROR_FAILURE;
    1970                 : 
    1971                 :     nsresult rv;
    1972                 : 
    1973               0 :     JSContext* cx = mContext;
    1974               0 :     JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE);
    1975               0 :     if (! xdr)
    1976               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1977               0 :     xdr->userdata = (void*) aStream;
    1978                 : 
    1979               0 :     JSAutoRequest ar(cx);
    1980               0 :     if (! ::JS_XDRScript(xdr, &aScriptObject)) {
    1981               0 :         rv = NS_ERROR_FAILURE;  // likely to be a principals serialization error
    1982                 :     } else {
    1983                 :         // Get the encoded JSXDRState data and write it.  The JSXDRState owns
    1984                 :         // this buffer memory and will free it beneath ::JS_XDRDestroy.
    1985                 :         //
    1986                 :         // If an XPCOM object needs to be written in the midst of the JS XDR
    1987                 :         // encoding process, the C++ code called back from the JS engine (e.g.,
    1988                 :         // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data
    1989                 :         // from the JSXDRState to aStream, then write the object, then return
    1990                 :         // to JS XDR code with xdr reset so new JS data is encoded at the front
    1991                 :         // of the xdr's data buffer.
    1992                 :         //
    1993                 :         // However many XPCOM objects are interleaved with JS XDR data in the
    1994                 :         // stream, when control returns here from ::JS_XDRScript, we'll have
    1995                 :         // one last buffer of data to write to aStream.
    1996                 : 
    1997                 :         uint32_t size;
    1998                 :         const char* data = reinterpret_cast<const char*>
    1999               0 :                                            (::JS_XDRMemGetData(xdr, &size));
    2000               0 :         NS_ASSERTION(data, "no decoded JSXDRState data!");
    2001                 : 
    2002               0 :         rv = aStream->Write32(size);
    2003               0 :         if (NS_SUCCEEDED(rv))
    2004               0 :             rv = aStream->WriteBytes(data, size);
    2005                 :     }
    2006                 : 
    2007               0 :     ::JS_XDRDestroy(xdr);
    2008               0 :     if (NS_FAILED(rv)) return rv;
    2009                 : 
    2010               0 :     return rv;
    2011                 : }
    2012                 : 
    2013                 : nsresult
    2014               0 : nsJSContext::Deserialize(nsIObjectInputStream* aStream,
    2015                 :                          nsScriptObjectHolder<JSScript>& aResult)
    2016                 : {
    2017                 :     NS_TIME_FUNCTION_MIN(1.0);
    2018                 : 
    2019                 :     PRUint32 size;
    2020               0 :     nsresult rv = aStream->Read32(&size);
    2021               0 :     if (NS_FAILED(rv)) return rv;
    2022                 : 
    2023                 :     char* data;
    2024               0 :     rv = aStream->ReadBytes(size, &data);
    2025               0 :     if (NS_FAILED(rv)) return rv;
    2026                 : 
    2027               0 :     JSContext* cx = mContext;
    2028                 : 
    2029               0 :     JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_DECODE);
    2030               0 :     JSScript *result = nsnull;
    2031               0 :     if (! xdr) {
    2032               0 :         rv = NS_ERROR_OUT_OF_MEMORY;
    2033                 :     } else {
    2034               0 :         xdr->userdata = (void*) aStream;
    2035               0 :         JSAutoRequest ar(cx);
    2036               0 :         ::JS_XDRMemSetData(xdr, data, size);
    2037                 : 
    2038               0 :         if (! ::JS_XDRScript(xdr, &result)) {
    2039               0 :             rv = NS_ERROR_FAILURE;  // principals deserialization error?
    2040                 :         }
    2041                 : 
    2042                 :         // Update data in case ::JS_XDRScript called back into C++ code to
    2043                 :         // read an XPCOM object.
    2044                 :         //
    2045                 :         // In that case, the serialization process must have flushed a run
    2046                 :         // of counted bytes containing JS data at the point where the XPCOM
    2047                 :         // object starts, after which an encoding C++ callback from the JS
    2048                 :         // XDR code must have written the XPCOM object directly into the
    2049                 :         // nsIObjectOutputStream.
    2050                 :         //
    2051                 :         // The deserialization process will XDR-decode counted bytes up to
    2052                 :         // but not including the XPCOM object, then call back into C++ to
    2053                 :         // read the object, then read more counted bytes and hand them off
    2054                 :         // to the JSXDRState, so more JS data can be decoded.
    2055                 :         //
    2056                 :         // This interleaving of JS XDR data and XPCOM object data may occur
    2057                 :         // several times beneath the call to ::JS_XDRScript, above.  At the
    2058                 :         // end of the day, we need to free (via nsMemory) the data owned by
    2059                 :         // the JSXDRState.  So we steal it back, nulling xdr's buffer so it
    2060                 :         // doesn't get passed to ::JS_free by ::JS_XDRDestroy.
    2061                 : 
    2062                 :         uint32_t junk;
    2063               0 :         data = (char*) ::JS_XDRMemGetData(xdr, &junk);
    2064               0 :         if (data)
    2065               0 :             ::JS_XDRMemSetData(xdr, NULL, 0);
    2066               0 :         ::JS_XDRDestroy(xdr);
    2067                 :     }
    2068                 : 
    2069                 :     // If data is null now, it must have been freed while deserializing an
    2070                 :     // XPCOM object (e.g., a principal) beneath ::JS_XDRScript.
    2071               0 :     if (data)
    2072               0 :         nsMemory::Free(data);
    2073               0 :     NS_ASSERTION(aResult.getScriptTypeID()==JAVASCRIPT,
    2074                 :                  "Expecting JS script object holder");
    2075                 : 
    2076                 :     // Now that we've cleaned up, handle the case when rv is a failure
    2077                 :     // code, which could happen for all sorts of reasons above.
    2078               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2079                 : 
    2080               0 :     return aResult.set(result);
    2081                 : }
    2082                 : 
    2083                 : nsIScriptGlobalObject *
    2084               0 : nsJSContext::GetGlobalObject()
    2085                 : {
    2086               0 :   JSObject *global = ::JS_GetGlobalObject(mContext);
    2087                 : 
    2088               0 :   if (!global) {
    2089               0 :     return nsnull;
    2090                 :   }
    2091                 : 
    2092               0 :   if (mGlobalObjectRef)
    2093               0 :     return mGlobalObjectRef;
    2094                 : 
    2095                 : #ifdef DEBUG
    2096                 :   {
    2097               0 :     JSObject *inner = JS_ObjectToInnerObject(mContext, global);
    2098                 : 
    2099                 :     // If this assertion hits then it means that we have a window object as
    2100                 :     // our global, but we never called CreateOuterObject.
    2101               0 :     NS_ASSERTION(inner == global, "Shouldn't be able to innerize here");
    2102                 :   }
    2103                 : #endif
    2104                 : 
    2105               0 :   JSClass *c = JS_GetClass(global);
    2106                 : 
    2107               0 :   if (!c || ((~c->flags) & (JSCLASS_HAS_PRIVATE |
    2108                 :                             JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
    2109               0 :     return nsnull;
    2110                 :   }
    2111                 : 
    2112               0 :   nsISupports *priv = (nsISupports *)js::GetObjectPrivate(global);
    2113                 : 
    2114                 :   nsCOMPtr<nsIXPConnectWrappedNative> wrapped_native =
    2115               0 :     do_QueryInterface(priv);
    2116                 : 
    2117               0 :   nsCOMPtr<nsIScriptGlobalObject> sgo;
    2118               0 :   if (wrapped_native) {
    2119                 :     // The global object is a XPConnect wrapped native, the native in
    2120                 :     // the wrapper might be the nsIScriptGlobalObject
    2121                 : 
    2122               0 :     sgo = do_QueryWrappedNative(wrapped_native);
    2123                 :   } else {
    2124               0 :     sgo = do_QueryInterface(priv);
    2125                 :   }
    2126                 : 
    2127                 :   // This'll return a pointer to something we're about to release, but
    2128                 :   // that's ok, the JS object will hold it alive long enough.
    2129               0 :   return sgo;
    2130                 : }
    2131                 : 
    2132                 : JSObject*
    2133               0 : nsJSContext::GetNativeGlobal()
    2134                 : {
    2135               0 :     return JS_GetGlobalObject(mContext);
    2136                 : }
    2137                 : 
    2138                 : nsresult
    2139               0 : nsJSContext::CreateNativeGlobalForInner(
    2140                 :                                 nsIScriptGlobalObject *aNewInner,
    2141                 :                                 bool aIsChrome,
    2142                 :                                 nsIPrincipal *aPrincipal,
    2143                 :                                 JSObject** aNativeGlobal, nsISupports **aHolder)
    2144                 : {
    2145               0 :   nsIXPConnect *xpc = nsContentUtils::XPConnect();
    2146               0 :   PRUint32 flags = aIsChrome? nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT : 0;
    2147                 : 
    2148               0 :   nsCOMPtr<nsIPrincipal> systemPrincipal;
    2149               0 :   if (aIsChrome) {
    2150               0 :     nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
    2151               0 :     ssm->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
    2152                 :   }
    2153                 : 
    2154               0 :   nsRefPtr<nsIXPConnectJSObjectHolder> jsholder;
    2155                 :   nsresult rv = xpc->
    2156                 :           InitClassesWithNewWrappedGlobal(mContext, aNewInner,
    2157                 :                                           aIsChrome ? systemPrincipal.get() : aPrincipal,
    2158               0 :                                           flags, getter_AddRefs(jsholder));
    2159               0 :   if (NS_FAILED(rv)) {
    2160               0 :     return rv;
    2161                 :   }
    2162               0 :   jsholder->GetJSObject(aNativeGlobal);
    2163               0 :   jsholder.forget(aHolder);
    2164               0 :   return NS_OK;
    2165                 : }
    2166                 : 
    2167                 : nsresult
    2168               0 : nsJSContext::ConnectToInner(nsIScriptGlobalObject *aNewInner, JSObject *aOuterGlobal)
    2169                 : {
    2170               0 :   NS_ENSURE_ARG(aNewInner);
    2171                 : #ifdef DEBUG
    2172               0 :   JSObject *newInnerJSObject = aNewInner->GetGlobalJSObject();
    2173                 : #endif
    2174                 : 
    2175                 :   // Now that we're connecting the outer global to the inner one,
    2176                 :   // we must have transplanted it. The JS engine tries to maintain
    2177                 :   // the global object's compartment as its default compartment,
    2178                 :   // so update that now since it might have changed.
    2179               0 :   JS_SetGlobalObject(mContext, aOuterGlobal);
    2180               0 :   NS_ASSERTION(JS_GetPrototype(aOuterGlobal) ==
    2181                 :                JS_GetPrototype(newInnerJSObject),
    2182                 :                "outer and inner globals should have the same prototype");
    2183                 : 
    2184               0 :   return NS_OK;
    2185                 : }
    2186                 : 
    2187                 : JSContext*
    2188               0 : nsJSContext::GetNativeContext()
    2189                 : {
    2190               0 :   return mContext;
    2191                 : }
    2192                 : 
    2193                 : nsresult
    2194               0 : nsJSContext::InitContext()
    2195                 : {
    2196                 :   // Make sure callers of this use
    2197                 :   // WillInitializeContext/DidInitializeContext around this call.
    2198               0 :   NS_ENSURE_TRUE(!mIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
    2199                 : 
    2200               0 :   if (!mContext)
    2201               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2202                 : 
    2203               0 :   ::JS_SetErrorReporter(mContext, NS_ScriptErrorReporter);
    2204                 : 
    2205               0 :   return NS_OK;
    2206                 : }
    2207                 : 
    2208                 : nsresult
    2209               0 : nsJSContext::CreateOuterObject(nsIScriptGlobalObject *aGlobalObject,
    2210                 :                                nsIScriptGlobalObject *aCurrentInner)
    2211                 : {
    2212               0 :   mGlobalObjectRef = aGlobalObject;
    2213                 : 
    2214               0 :   nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aGlobalObject));
    2215                 : 
    2216               0 :   if (chromeWindow) {
    2217                 :     // Always enable E4X for XUL and other chrome content -- there is no
    2218                 :     // need to preserve the <!-- script hiding hack from JS-in-HTML daze
    2219                 :     // (introduced in 1995 for graceful script degradation in Netscape 1,
    2220                 :     // Mosaic, and other pre-JS browsers).
    2221               0 :     JS_SetOptions(mContext, JS_GetOptions(mContext) | JSOPTION_XML);
    2222                 :   }
    2223                 : 
    2224                 :   JSObject *outer =
    2225               0 :     NS_NewOuterWindowProxy(mContext, aCurrentInner->GetGlobalJSObject());
    2226               0 :   if (!outer) {
    2227               0 :     return NS_ERROR_FAILURE;
    2228                 :   }
    2229                 : 
    2230               0 :   js::SetProxyExtra(outer, 0, js::PrivateValue(aGlobalObject));
    2231                 : 
    2232               0 :   return SetOuterObject(outer);
    2233                 : }
    2234                 : 
    2235                 : nsresult
    2236               0 : nsJSContext::SetOuterObject(JSObject* aOuterObject)
    2237                 : {
    2238                 :   // Force our context's global object to be the outer.
    2239                 :   // NB: JS_SetGlobalObject sets mContext->compartment.
    2240               0 :   JS_SetGlobalObject(mContext, aOuterObject);
    2241                 : 
    2242                 :   // Set up the prototype for the outer object.
    2243               0 :   JSObject *inner = JS_GetParent(aOuterObject);
    2244               0 :   JS_SetPrototype(mContext, aOuterObject, JS_GetPrototype(inner));
    2245                 : 
    2246               0 :   return NS_OK;
    2247                 : }
    2248                 : 
    2249                 : nsresult
    2250               0 : nsJSContext::InitOuterWindow()
    2251                 : {
    2252               0 :   JSObject *global = JS_ObjectToInnerObject(mContext, JS_GetGlobalObject(mContext));
    2253                 : 
    2254               0 :   nsresult rv = InitClasses(global); // this will complete global object initialization
    2255               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2256                 : 
    2257               0 :   return NS_OK;
    2258                 : }
    2259                 : 
    2260                 : nsresult
    2261               0 : nsJSContext::InitializeExternalClasses()
    2262                 : {
    2263               0 :   nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
    2264               0 :   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
    2265                 : 
    2266               0 :   return nameSpaceManager->InitForContext(this);
    2267                 : }
    2268                 : 
    2269                 : nsresult
    2270               0 : nsJSContext::SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aArgs)
    2271                 : {
    2272                 :   PRUint32  argc;
    2273               0 :   jsval    *argv = nsnull;
    2274                 : 
    2275               0 :   JSAutoRequest ar(mContext);
    2276                 : 
    2277               0 :   Maybe<nsRootedJSValueArray> tempStorage;
    2278                 : 
    2279                 :   nsresult rv =
    2280               0 :     ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
    2281               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2282                 : 
    2283                 :   jsval vargs;
    2284                 : 
    2285                 :   // got the arguments, now attach them.
    2286                 : 
    2287                 :   // window.dialogArguments is supposed to be an array if a JS array
    2288                 :   // was passed to showModalDialog(), deal with that here.
    2289               0 :   if (strcmp(aPropName, "dialogArguments") == 0 && argc <= 1) {
    2290               0 :     vargs = argc ? argv[0] : JSVAL_VOID;
    2291                 :   } else {
    2292               0 :     for (PRUint32 i = 0; i < argc; ++i) {
    2293               0 :       if (!JS_WrapValue(mContext, &argv[i])) {
    2294               0 :         return NS_ERROR_FAILURE;
    2295                 :       }
    2296                 :     }
    2297                 : 
    2298               0 :     JSObject *args = ::JS_NewArrayObject(mContext, argc, argv);
    2299               0 :     vargs = OBJECT_TO_JSVAL(args);
    2300                 :   }
    2301                 : 
    2302                 :   // Make sure to use JS_DefineProperty here so that we can override
    2303                 :   // readonly XPConnect properties here as well (read dialogArguments).
    2304               0 :   return JS_DefineProperty(mContext, aTarget, aPropName, vargs, NULL, NULL, 0)
    2305                 :     ? NS_OK
    2306               0 :     : NS_ERROR_FAILURE;
    2307                 : }
    2308                 : 
    2309                 : nsresult
    2310               0 : nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
    2311                 :                                      JSObject *aScope,
    2312                 :                                      PRUint32 *aArgc,
    2313                 :                                      jsval **aArgv,
    2314                 :                                      Maybe<nsRootedJSValueArray> &aTempStorage)
    2315                 : {
    2316               0 :   nsresult rv = NS_OK;
    2317                 : 
    2318                 :   // If the array implements nsIJSArgArray, just grab the values directly.
    2319               0 :   nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
    2320               0 :   if (fastArray != nsnull)
    2321               0 :     return fastArray->GetArgs(aArgc, reinterpret_cast<void **>(aArgv));
    2322                 : 
    2323                 :   // Take the slower path converting each item.
    2324                 :   // Handle only nsIArray and nsIVariant.  nsIArray is only needed for
    2325                 :   // SetProperty('arguments', ...);
    2326                 : 
    2327               0 :   *aArgv = nsnull;
    2328               0 :   *aArgc = 0;
    2329                 : 
    2330               0 :   nsIXPConnect *xpc = nsContentUtils::XPConnect();
    2331               0 :   NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
    2332                 : 
    2333               0 :   if (!aArgs)
    2334               0 :     return NS_OK;
    2335                 :   PRUint32 argCount;
    2336                 :   // This general purpose function may need to convert an arg array
    2337                 :   // (window.arguments, event-handler args) and a generic property.
    2338               0 :   nsCOMPtr<nsIArray> argsArray(do_QueryInterface(aArgs));
    2339                 : 
    2340               0 :   if (argsArray) {
    2341               0 :     rv = argsArray->GetLength(&argCount);
    2342               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2343               0 :     if (argCount == 0)
    2344               0 :       return NS_OK;
    2345                 :   } else {
    2346               0 :     argCount = 1; // the nsISupports which is not an array
    2347                 :   }
    2348                 : 
    2349                 :   // Use the caller's auto guards to release and unroot.
    2350               0 :   aTempStorage.construct(mContext);
    2351               0 :   bool ok = aTempStorage.ref().SetCapacity(mContext, argCount);
    2352               0 :   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
    2353               0 :   jsval *argv = aTempStorage.ref().Elements();
    2354                 : 
    2355               0 :   if (argsArray) {
    2356               0 :     for (PRUint32 argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
    2357               0 :       nsCOMPtr<nsISupports> arg;
    2358               0 :       jsval *thisval = argv + argCtr;
    2359               0 :       argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
    2360               0 :                                 getter_AddRefs(arg));
    2361               0 :       if (!arg) {
    2362               0 :         *thisval = JSVAL_NULL;
    2363               0 :         continue;
    2364                 :       }
    2365               0 :       nsCOMPtr<nsIVariant> variant(do_QueryInterface(arg));
    2366               0 :       if (variant != nsnull) {
    2367               0 :         rv = xpc->VariantToJS(mContext, aScope, variant, thisval);
    2368                 :       } else {
    2369                 :         // And finally, support the nsISupportsPrimitives supplied
    2370                 :         // by the AppShell.  It generally will pass only strings, but
    2371                 :         // as we have code for handling all, we may as well use it.
    2372               0 :         rv = AddSupportsPrimitiveTojsvals(arg, thisval);
    2373               0 :         if (rv == NS_ERROR_NO_INTERFACE) {
    2374                 :           // something else - probably an event object or similar -
    2375                 :           // just wrap it.
    2376                 : #ifdef NS_DEBUG
    2377                 :           // but first, check its not another nsISupportsPrimitive, as
    2378                 :           // these are now deprecated for use with script contexts.
    2379               0 :           nsCOMPtr<nsISupportsPrimitive> prim(do_QueryInterface(arg));
    2380               0 :           NS_ASSERTION(prim == nsnull,
    2381                 :                        "Don't pass nsISupportsPrimitives - use nsIVariant!");
    2382                 : #endif
    2383               0 :           nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
    2384                 :           jsval v;
    2385                 :           rv = nsContentUtils::WrapNative(mContext, aScope, arg, &v,
    2386               0 :                                           getter_AddRefs(wrapper));
    2387               0 :           if (NS_SUCCEEDED(rv)) {
    2388               0 :             *thisval = v;
    2389                 :           }
    2390                 :         }
    2391                 :       }
    2392                 :     }
    2393                 :   } else {
    2394               0 :     nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs);
    2395               0 :     if (variant) {
    2396               0 :       rv = xpc->VariantToJS(mContext, aScope, variant, argv);
    2397                 :     } else {
    2398               0 :       NS_ERROR("Not an array, not an interface?");
    2399               0 :       rv = NS_ERROR_UNEXPECTED;
    2400                 :     }
    2401                 :   }
    2402               0 :   if (NS_FAILED(rv))
    2403               0 :     return rv;
    2404               0 :   *aArgv = argv;
    2405               0 :   *aArgc = argCount;
    2406               0 :   return NS_OK;
    2407                 : }
    2408                 : 
    2409                 : // This really should go into xpconnect somewhere...
    2410                 : nsresult
    2411               0 : nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv)
    2412                 : {
    2413               0 :   NS_PRECONDITION(aArg, "Empty arg");
    2414                 : 
    2415               0 :   nsCOMPtr<nsISupportsPrimitive> argPrimitive(do_QueryInterface(aArg));
    2416               0 :   if (!argPrimitive)
    2417               0 :     return NS_ERROR_NO_INTERFACE;
    2418                 : 
    2419               0 :   JSContext *cx = mContext;
    2420                 :   PRUint16 type;
    2421               0 :   argPrimitive->GetType(&type);
    2422                 : 
    2423               0 :   switch(type) {
    2424                 :     case nsISupportsPrimitive::TYPE_CSTRING : {
    2425               0 :       nsCOMPtr<nsISupportsCString> p(do_QueryInterface(argPrimitive));
    2426               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2427                 : 
    2428               0 :       nsCAutoString data;
    2429                 : 
    2430               0 :       p->GetData(data);
    2431                 : 
    2432                 : 
    2433               0 :       JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
    2434               0 :       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    2435                 : 
    2436               0 :       *aArgv = STRING_TO_JSVAL(str);
    2437                 : 
    2438               0 :       break;
    2439                 :     }
    2440                 :     case nsISupportsPrimitive::TYPE_STRING : {
    2441               0 :       nsCOMPtr<nsISupportsString> p(do_QueryInterface(argPrimitive));
    2442               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2443                 : 
    2444               0 :       nsAutoString data;
    2445                 : 
    2446               0 :       p->GetData(data);
    2447                 : 
    2448                 :       // cast is probably safe since wchar_t and jschar are expected
    2449                 :       // to be equivalent; both unsigned 16-bit entities
    2450                 :       JSString *str =
    2451                 :         ::JS_NewUCStringCopyN(cx,
    2452               0 :                               reinterpret_cast<const jschar *>(data.get()),
    2453               0 :                               data.Length());
    2454               0 :       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    2455                 : 
    2456               0 :       *aArgv = STRING_TO_JSVAL(str);
    2457               0 :       break;
    2458                 :     }
    2459                 :     case nsISupportsPrimitive::TYPE_PRBOOL : {
    2460               0 :       nsCOMPtr<nsISupportsPRBool> p(do_QueryInterface(argPrimitive));
    2461               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2462                 : 
    2463                 :       bool data;
    2464                 : 
    2465               0 :       p->GetData(&data);
    2466                 : 
    2467               0 :       *aArgv = BOOLEAN_TO_JSVAL(data);
    2468                 : 
    2469               0 :       break;
    2470                 :     }
    2471                 :     case nsISupportsPrimitive::TYPE_PRUINT8 : {
    2472               0 :       nsCOMPtr<nsISupportsPRUint8> p(do_QueryInterface(argPrimitive));
    2473               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2474                 : 
    2475                 :       PRUint8 data;
    2476                 : 
    2477               0 :       p->GetData(&data);
    2478                 : 
    2479               0 :       *aArgv = INT_TO_JSVAL(data);
    2480                 : 
    2481               0 :       break;
    2482                 :     }
    2483                 :     case nsISupportsPrimitive::TYPE_PRUINT16 : {
    2484               0 :       nsCOMPtr<nsISupportsPRUint16> p(do_QueryInterface(argPrimitive));
    2485               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2486                 : 
    2487                 :       PRUint16 data;
    2488                 : 
    2489               0 :       p->GetData(&data);
    2490                 : 
    2491               0 :       *aArgv = INT_TO_JSVAL(data);
    2492                 : 
    2493               0 :       break;
    2494                 :     }
    2495                 :     case nsISupportsPrimitive::TYPE_PRUINT32 : {
    2496               0 :       nsCOMPtr<nsISupportsPRUint32> p(do_QueryInterface(argPrimitive));
    2497               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2498                 : 
    2499                 :       PRUint32 data;
    2500                 : 
    2501               0 :       p->GetData(&data);
    2502                 : 
    2503               0 :       *aArgv = INT_TO_JSVAL(data);
    2504                 : 
    2505               0 :       break;
    2506                 :     }
    2507                 :     case nsISupportsPrimitive::TYPE_CHAR : {
    2508               0 :       nsCOMPtr<nsISupportsChar> p(do_QueryInterface(argPrimitive));
    2509               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2510                 : 
    2511                 :       char data;
    2512                 : 
    2513               0 :       p->GetData(&data);
    2514                 : 
    2515               0 :       JSString *str = ::JS_NewStringCopyN(cx, &data, 1);
    2516               0 :       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
    2517                 : 
    2518               0 :       *aArgv = STRING_TO_JSVAL(str);
    2519                 : 
    2520               0 :       break;
    2521                 :     }
    2522                 :     case nsISupportsPrimitive::TYPE_PRINT16 : {
    2523               0 :       nsCOMPtr<nsISupportsPRInt16> p(do_QueryInterface(argPrimitive));
    2524               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2525                 : 
    2526                 :       PRInt16 data;
    2527                 : 
    2528               0 :       p->GetData(&data);
    2529                 : 
    2530               0 :       *aArgv = INT_TO_JSVAL(data);
    2531                 : 
    2532               0 :       break;
    2533                 :     }
    2534                 :     case nsISupportsPrimitive::TYPE_PRINT32 : {
    2535               0 :       nsCOMPtr<nsISupportsPRInt32> p(do_QueryInterface(argPrimitive));
    2536               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2537                 : 
    2538                 :       PRInt32 data;
    2539                 : 
    2540               0 :       p->GetData(&data);
    2541                 : 
    2542               0 :       *aArgv = INT_TO_JSVAL(data);
    2543                 : 
    2544               0 :       break;
    2545                 :     }
    2546                 :     case nsISupportsPrimitive::TYPE_FLOAT : {
    2547               0 :       nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
    2548               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2549                 : 
    2550                 :       float data;
    2551                 : 
    2552               0 :       p->GetData(&data);
    2553                 : 
    2554               0 :       JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
    2555               0 :       NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
    2556                 : 
    2557               0 :       break;
    2558                 :     }
    2559                 :     case nsISupportsPrimitive::TYPE_DOUBLE : {
    2560               0 :       nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
    2561               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2562                 : 
    2563                 :       double data;
    2564                 : 
    2565               0 :       p->GetData(&data);
    2566                 : 
    2567               0 :       JSBool ok = ::JS_NewNumberValue(cx, data, aArgv);
    2568               0 :       NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
    2569                 : 
    2570               0 :       break;
    2571                 :     }
    2572                 :     case nsISupportsPrimitive::TYPE_INTERFACE_POINTER : {
    2573               0 :       nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
    2574               0 :       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
    2575                 : 
    2576               0 :       nsCOMPtr<nsISupports> data;
    2577               0 :       nsIID *iid = nsnull;
    2578                 : 
    2579               0 :       p->GetData(getter_AddRefs(data));
    2580               0 :       p->GetDataIID(&iid);
    2581               0 :       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
    2582                 : 
    2583               0 :       AutoFree iidGuard(iid); // Free iid upon destruction.
    2584                 : 
    2585               0 :       nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
    2586                 :       jsval v;
    2587                 :       nsresult rv = nsContentUtils::WrapNative(cx, ::JS_GetGlobalObject(cx),
    2588                 :                                                data, iid, &v,
    2589               0 :                                                getter_AddRefs(wrapper));
    2590               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2591                 : 
    2592               0 :       *aArgv = v;
    2593                 : 
    2594               0 :       break;
    2595                 :     }
    2596                 :     case nsISupportsPrimitive::TYPE_ID :
    2597                 :     case nsISupportsPrimitive::TYPE_PRUINT64 :
    2598                 :     case nsISupportsPrimitive::TYPE_PRINT64 :
    2599                 :     case nsISupportsPrimitive::TYPE_PRTIME :
    2600                 :     case nsISupportsPrimitive::TYPE_VOID : {
    2601               0 :       NS_WARNING("Unsupported primitive type used");
    2602               0 :       *aArgv = JSVAL_NULL;
    2603               0 :       break;
    2604                 :     }
    2605                 :     default : {
    2606               0 :       NS_WARNING("Unknown primitive type used");
    2607               0 :       *aArgv = JSVAL_NULL;
    2608               0 :       break;
    2609                 :     }
    2610                 :   }
    2611               0 :   return NS_OK;
    2612                 : }
    2613                 : 
    2614                 : #ifdef NS_TRACE_MALLOC
    2615                 : 
    2616                 : #include <errno.h>              // XXX assume Linux if NS_TRACE_MALLOC
    2617                 : #include <fcntl.h>
    2618                 : #ifdef XP_UNIX
    2619                 : #include <unistd.h>
    2620                 : #endif
    2621                 : #ifdef XP_WIN32
    2622                 : #include <io.h>
    2623                 : #endif
    2624                 : #include "nsTraceMalloc.h"
    2625                 : 
    2626                 : static JSBool
    2627                 : CheckUniversalXPConnectForTraceMalloc(JSContext *cx)
    2628                 : {
    2629                 :     bool hasCap = false;
    2630                 :     nsresult rv = nsContentUtils::GetSecurityManager()->
    2631                 :                     IsCapabilityEnabled("UniversalXPConnect", &hasCap);
    2632                 :     if (NS_SUCCEEDED(rv) && hasCap)
    2633                 :         return JS_TRUE;
    2634                 :     JS_ReportError(cx, "trace-malloc functions require UniversalXPConnect");
    2635                 :     return JS_FALSE;
    2636                 : }
    2637                 : 
    2638                 : static JSBool
    2639                 : TraceMallocDisable(JSContext *cx, unsigned argc, jsval *vp)
    2640                 : {
    2641                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2642                 :         return JS_FALSE;
    2643                 : 
    2644                 :     NS_TraceMallocDisable();
    2645                 :     JS_SET_RVAL(cx, vp, JSVAL_VOID);
    2646                 :     return JS_TRUE;
    2647                 : }
    2648                 : 
    2649                 : static JSBool
    2650                 : TraceMallocEnable(JSContext *cx, unsigned argc, jsval *vp)
    2651                 : {
    2652                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2653                 :         return JS_FALSE;
    2654                 : 
    2655                 :     NS_TraceMallocEnable();
    2656                 :     JS_SET_RVAL(cx, vp, JSVAL_VOID);
    2657                 :     return JS_TRUE;
    2658                 : }
    2659                 : 
    2660                 : static JSBool
    2661                 : TraceMallocOpenLogFile(JSContext *cx, unsigned argc, jsval *vp)
    2662                 : {
    2663                 :     int fd;
    2664                 :     JSString *str;
    2665                 : 
    2666                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2667                 :         return JS_FALSE;
    2668                 : 
    2669                 :     if (argc == 0) {
    2670                 :         fd = -1;
    2671                 :     } else {
    2672                 :         str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
    2673                 :         if (!str)
    2674                 :             return JS_FALSE;
    2675                 :         JSAutoByteString filename(cx, str);
    2676                 :         if (!filename)
    2677                 :             return JS_FALSE;
    2678                 :         fd = open(filename.ptr(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
    2679                 :         if (fd < 0) {
    2680                 :             JS_ReportError(cx, "can't open %s: %s", filename.ptr(), strerror(errno));
    2681                 :             return JS_FALSE;
    2682                 :         }
    2683                 :     }
    2684                 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(fd));
    2685                 :     return JS_TRUE;
    2686                 : }
    2687                 : 
    2688                 : static JSBool
    2689                 : TraceMallocChangeLogFD(JSContext *cx, unsigned argc, jsval *vp)
    2690                 : {
    2691                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2692                 :         return JS_FALSE;
    2693                 : 
    2694                 :     int32_t fd, oldfd;
    2695                 :     if (argc == 0) {
    2696                 :         oldfd = -1;
    2697                 :     } else {
    2698                 :         if (!JS_ValueToECMAInt32(cx, JS_ARGV(cx, vp)[0], &fd))
    2699                 :             return JS_FALSE;
    2700                 :         oldfd = NS_TraceMallocChangeLogFD(fd);
    2701                 :         if (oldfd == -2) {
    2702                 :             JS_ReportOutOfMemory(cx);
    2703                 :             return JS_FALSE;
    2704                 :         }
    2705                 :     }
    2706                 :     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(oldfd));
    2707                 :     return JS_TRUE;
    2708                 : }
    2709                 : 
    2710                 : static JSBool
    2711                 : TraceMallocCloseLogFD(JSContext *cx, unsigned argc, jsval *vp)
    2712                 : {
    2713                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2714                 :         return JS_FALSE;
    2715                 : 
    2716                 :     int32_t fd;
    2717                 :     JS_SET_RVAL(cx, vp, JSVAL_VOID);
    2718                 :     if (argc == 0)
    2719                 :         return JS_TRUE;
    2720                 :     if (!JS_ValueToECMAInt32(cx, JS_ARGV(cx, vp)[0], &fd))
    2721                 :         return JS_FALSE;
    2722                 :     NS_TraceMallocCloseLogFD((int) fd);
    2723                 :     return JS_TRUE;
    2724                 : }
    2725                 : 
    2726                 : static JSBool
    2727                 : TraceMallocLogTimestamp(JSContext *cx, unsigned argc, jsval *vp)
    2728                 : {
    2729                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2730                 :         return JS_FALSE;
    2731                 : 
    2732                 :     JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
    2733                 :     if (!str)
    2734                 :         return JS_FALSE;
    2735                 :     JSAutoByteString caption(cx, str);
    2736                 :     if (!caption)
    2737                 :         return JS_FALSE;
    2738                 :     NS_TraceMallocLogTimestamp(caption.ptr());
    2739                 :     JS_SET_RVAL(cx, vp, JSVAL_VOID);
    2740                 :     return JS_TRUE;
    2741                 : }
    2742                 : 
    2743                 : static JSBool
    2744                 : TraceMallocDumpAllocations(JSContext *cx, unsigned argc, jsval *vp)
    2745                 : {
    2746                 :     if (!CheckUniversalXPConnectForTraceMalloc(cx))
    2747                 :         return JS_FALSE;
    2748                 : 
    2749                 :     JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
    2750                 :     if (!str)
    2751                 :         return JS_FALSE;
    2752                 :     JSAutoByteString pathname(cx, str);
    2753                 :     if (!pathname)
    2754                 :         return JS_FALSE;
    2755                 :     if (NS_TraceMallocDumpAllocations(pathname.ptr()) < 0) {
    2756                 :         JS_ReportError(cx, "can't dump to %s: %s", pathname.ptr(), strerror(errno));
    2757                 :         return JS_FALSE;
    2758                 :     }
    2759                 :     JS_SET_RVAL(cx, vp, JSVAL_VOID);
    2760                 :     return JS_TRUE;
    2761                 : }
    2762                 : 
    2763                 : static JSFunctionSpec TraceMallocFunctions[] = {
    2764                 :     {"TraceMallocDisable",         TraceMallocDisable,         0, 0},
    2765                 :     {"TraceMallocEnable",          TraceMallocEnable,          0, 0},
    2766                 :     {"TraceMallocOpenLogFile",     TraceMallocOpenLogFile,     1, 0},
    2767                 :     {"TraceMallocChangeLogFD",     TraceMallocChangeLogFD,     1, 0},
    2768                 :     {"TraceMallocCloseLogFD",      TraceMallocCloseLogFD,      1, 0},
    2769                 :     {"TraceMallocLogTimestamp",    TraceMallocLogTimestamp,    1, 0},
    2770                 :     {"TraceMallocDumpAllocations", TraceMallocDumpAllocations, 1, 0},
    2771                 :     {nsnull,                       nsnull,                     0, 0}
    2772                 : };
    2773                 : 
    2774                 : #endif /* NS_TRACE_MALLOC */
    2775                 : 
    2776                 : #ifdef MOZ_JPROF
    2777                 : 
    2778                 : #include <signal.h>
    2779                 : 
    2780                 : inline bool
    2781                 : IsJProfAction(struct sigaction *action)
    2782                 : {
    2783                 :     return (action->sa_sigaction &&
    2784                 :             (action->sa_flags & (SA_RESTART | SA_SIGINFO)) == (SA_RESTART | SA_SIGINFO));
    2785                 : }
    2786                 : 
    2787                 : void NS_JProfStartProfiling();
    2788                 : void NS_JProfStopProfiling();
    2789                 : void NS_JProfClearCircular();
    2790                 : 
    2791                 : static JSBool
    2792                 : JProfStartProfilingJS(JSContext *cx, unsigned argc, jsval *vp)
    2793                 : {
    2794                 :   NS_JProfStartProfiling();
    2795                 :   return JS_TRUE;
    2796                 : }
    2797                 : 
    2798                 : void NS_JProfStartProfiling()
    2799                 : {
    2800                 :     // Figure out whether we're dealing with SIGPROF, SIGALRM, or
    2801                 :     // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
    2802                 :     // JP_RTC_HZ)
    2803                 :     struct sigaction action;
    2804                 : 
    2805                 :     // Must check ALRM before PROF since both are enabled for real-time
    2806                 :     sigaction(SIGALRM, nsnull, &action);
    2807                 :     //printf("SIGALRM: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
    2808                 :     if (IsJProfAction(&action)) {
    2809                 :         //printf("Beginning real-time jprof profiling.\n");
    2810                 :         raise(SIGALRM);
    2811                 :         return;
    2812                 :     }
    2813                 : 
    2814                 :     sigaction(SIGPROF, nsnull, &action);
    2815                 :     //printf("SIGPROF: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
    2816                 :     if (IsJProfAction(&action)) {
    2817                 :         //printf("Beginning process-time jprof profiling.\n");
    2818                 :         raise(SIGPROF);
    2819                 :         return;
    2820                 :     }
    2821                 : 
    2822                 :     sigaction(SIGPOLL, nsnull, &action);
    2823                 :     //printf("SIGPOLL: %p, flags = %x\n",action.sa_sigaction,action.sa_flags);
    2824                 :     if (IsJProfAction(&action)) {
    2825                 :         //printf("Beginning rtc-based jprof profiling.\n");
    2826                 :         raise(SIGPOLL);
    2827                 :         return;
    2828                 :     }
    2829                 : 
    2830                 :     printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
    2831                 : }
    2832                 : 
    2833                 : static JSBool
    2834                 : JProfStopProfilingJS(JSContext *cx, unsigned argc, jsval *vp)
    2835                 : {
    2836                 :   NS_JProfStopProfiling();
    2837                 :   return JS_TRUE;
    2838                 : }
    2839                 : 
    2840                 : void
    2841                 : NS_JProfStopProfiling()
    2842                 : {
    2843                 :     raise(SIGUSR1);
    2844                 :     //printf("Stopped jprof profiling.\n");
    2845                 : }
    2846                 : 
    2847                 : static JSBool
    2848                 : JProfClearCircularJS(JSContext *cx, unsigned argc, jsval *vp)
    2849                 : {
    2850                 :   NS_JProfClearCircular();
    2851                 :   return JS_TRUE;
    2852                 : }
    2853                 : 
    2854                 : void
    2855                 : NS_JProfClearCircular()
    2856                 : {
    2857                 :     raise(SIGUSR2);
    2858                 :     //printf("cleared jprof buffer\n");
    2859                 : }
    2860                 : 
    2861                 : static JSBool
    2862                 : JProfSaveCircularJS(JSContext *cx, unsigned argc, jsval *vp)
    2863                 : {
    2864                 :   // Not ideal...
    2865                 :   NS_JProfStopProfiling();
    2866                 :   NS_JProfStartProfiling();
    2867                 :   return JS_TRUE;
    2868                 : }
    2869                 : 
    2870                 : static JSFunctionSpec JProfFunctions[] = {
    2871                 :     {"JProfStartProfiling",        JProfStartProfilingJS,      0, 0},
    2872                 :     {"JProfStopProfiling",         JProfStopProfilingJS,       0, 0},
    2873                 :     {"JProfClearCircular",         JProfClearCircularJS,       0, 0},
    2874                 :     {"JProfSaveCircular",          JProfSaveCircularJS,        0, 0},
    2875                 :     {nsnull,                       nsnull,                     0, 0}
    2876                 : };
    2877                 : 
    2878                 : #endif /* defined(MOZ_JPROF) */
    2879                 : 
    2880                 : #ifdef MOZ_DMD
    2881                 : 
    2882                 : // See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
    2883                 : // how to use DMD.
    2884                 : 
    2885                 : static JSBool
    2886                 : DMDCheckJS(JSContext *cx, unsigned argc, jsval *vp)
    2887                 : {
    2888                 :   mozilla::DMDCheckAndDump();
    2889                 :   return JS_TRUE;
    2890                 : }
    2891                 : 
    2892                 : static JSFunctionSpec DMDFunctions[] = {
    2893                 :     {"DMD",                        DMDCheckJS,                 0, 0},
    2894                 :     {nsnull,                       nsnull,                     0, 0}
    2895                 : };
    2896                 : 
    2897                 : #endif /* defined(MOZ_DMD) */
    2898                 : 
    2899                 : nsresult
    2900               0 : nsJSContext::InitClasses(JSObject* aGlobalObj)
    2901                 : {
    2902               0 :   nsresult rv = InitializeExternalClasses();
    2903               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2904                 : 
    2905               0 :   JSAutoRequest ar(mContext);
    2906                 : 
    2907               0 :   ::JS_SetOptions(mContext, mDefaultJSOptions);
    2908                 : 
    2909                 :   // Attempt to initialize profiling functions
    2910               0 :   ::JS_DefineProfilingFunctions(mContext, aGlobalObj);
    2911                 : 
    2912                 : #ifdef NS_TRACE_MALLOC
    2913                 :   // Attempt to initialize TraceMalloc functions
    2914                 :   ::JS_DefineFunctions(mContext, aGlobalObj, TraceMallocFunctions);
    2915                 : #endif
    2916                 : 
    2917                 : #ifdef MOZ_JPROF
    2918                 :   // Attempt to initialize JProf functions
    2919                 :   ::JS_DefineFunctions(mContext, aGlobalObj, JProfFunctions);
    2920                 : #endif
    2921                 : 
    2922                 : #ifdef MOZ_DMD
    2923                 :   // Attempt to initialize DMD functions
    2924                 :   ::JS_DefineFunctions(mContext, aGlobalObj, DMDFunctions);
    2925                 : #endif
    2926                 : 
    2927               0 :   JSOptionChangedCallback(js_options_dot_str, this);
    2928                 : 
    2929               0 :   return rv;
    2930                 : }
    2931                 : 
    2932                 : void
    2933               0 : nsJSContext::WillInitializeContext()
    2934                 : {
    2935               0 :   mIsInitialized = false;
    2936               0 : }
    2937                 : 
    2938                 : void
    2939               0 : nsJSContext::DidInitializeContext()
    2940                 : {
    2941               0 :   mIsInitialized = true;
    2942               0 : }
    2943                 : 
    2944                 : bool
    2945               0 : nsJSContext::IsContextInitialized()
    2946                 : {
    2947               0 :   return mIsInitialized;
    2948                 : }
    2949                 : 
    2950                 : void
    2951               0 : nsJSContext::ScriptEvaluated(bool aTerminated)
    2952                 : {
    2953               0 :   if (aTerminated && mTerminations) {
    2954                 :     // Make sure to null out mTerminations before doing anything that
    2955                 :     // might cause new termination funcs to be added!
    2956               0 :     nsJSContext::TerminationFuncClosure* start = mTerminations;
    2957               0 :     mTerminations = nsnull;
    2958                 : 
    2959               0 :     for (nsJSContext::TerminationFuncClosure* cur = start;
    2960                 :          cur;
    2961                 :          cur = cur->mNext) {
    2962               0 :       (*(cur->mTerminationFunc))(cur->mTerminationFuncArg);
    2963                 :     }
    2964               0 :     delete start;
    2965                 :   }
    2966                 : 
    2967               0 :   JS_MaybeGC(mContext);
    2968                 : 
    2969               0 :   if (aTerminated) {
    2970               0 :     mOperationCallbackTime = 0;
    2971               0 :     mModalStateTime = 0;
    2972                 :   }
    2973               0 : }
    2974                 : 
    2975                 : void
    2976               0 : nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc,
    2977                 :                                     nsIDOMWindow* aRef)
    2978                 : {
    2979               0 :   NS_PRECONDITION(GetExecutingScript(), "should be executing script");
    2980                 : 
    2981                 :   nsJSContext::TerminationFuncClosure* newClosure =
    2982               0 :     new nsJSContext::TerminationFuncClosure(aFunc, aRef, mTerminations);
    2983               0 :   mTerminations = newClosure;
    2984               0 : }
    2985                 : 
    2986                 : bool
    2987               0 : nsJSContext::GetScriptsEnabled()
    2988                 : {
    2989               0 :   return mScriptsEnabled;
    2990                 : }
    2991                 : 
    2992                 : void
    2993               0 : nsJSContext::SetScriptsEnabled(bool aEnabled, bool aFireTimeouts)
    2994                 : {
    2995                 :   // eeek - this seems the wrong way around - the global should callback
    2996                 :   // into each context, so every language is disabled.
    2997               0 :   mScriptsEnabled = aEnabled;
    2998                 : 
    2999               0 :   nsIScriptGlobalObject *global = GetGlobalObject();
    3000                 : 
    3001               0 :   if (global) {
    3002               0 :     global->SetScriptsEnabled(aEnabled, aFireTimeouts);
    3003                 :   }
    3004               0 : }
    3005                 : 
    3006                 : 
    3007                 : bool
    3008               0 : nsJSContext::GetProcessingScriptTag()
    3009                 : {
    3010               0 :   return mProcessingScriptTag;
    3011                 : }
    3012                 : 
    3013                 : void
    3014               0 : nsJSContext::SetProcessingScriptTag(bool aFlag)
    3015                 : {
    3016               0 :   mProcessingScriptTag = aFlag;
    3017               0 : }
    3018                 : 
    3019                 : bool
    3020               0 : nsJSContext::GetExecutingScript()
    3021                 : {
    3022               0 :   return JS_IsRunning(mContext) || mExecuteDepth > 0;
    3023                 : }
    3024                 : 
    3025                 : void
    3026               0 : nsJSContext::SetGCOnDestruction(bool aGCOnDestruction)
    3027                 : {
    3028               0 :   mGCOnDestruction = aGCOnDestruction;
    3029               0 : }
    3030                 : 
    3031                 : NS_IMETHODIMP
    3032               0 : nsJSContext::ScriptExecuted()
    3033                 : {
    3034               0 :   ScriptEvaluated(!::JS_IsRunning(mContext));
    3035                 : 
    3036               0 :   return NS_OK;
    3037                 : }
    3038                 : 
    3039                 : //static
    3040                 : void
    3041               4 : nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
    3042                 : {
    3043                 :   NS_TIME_FUNCTION_MIN(1.0);
    3044               8 :   SAMPLE_LABEL("GC", "GarbageCollectNow");
    3045                 : 
    3046               4 :   KillGCTimer();
    3047               4 :   KillShrinkGCBuffersTimer();
    3048                 : 
    3049                 :   // Reset sPendingLoadCount in case the timer that fired was a
    3050                 :   // timer we scheduled due to a normal GC timer firing while
    3051                 :   // documents were loading. If this happens we're waiting for a
    3052                 :   // document that is taking a long time to load, and we effectively
    3053                 :   // ignore the fact that the currently loading documents are still
    3054                 :   // loading and move on as if they weren't.
    3055               4 :   sPendingLoadCount = 0;
    3056               4 :   sLoadingInProgress = false;
    3057                 : 
    3058               4 :   if (nsContentUtils::XPConnect()) {
    3059               4 :     nsContentUtils::XPConnect()->GarbageCollect(reason, gckind);
    3060                 :   }
    3061               4 : }
    3062                 : 
    3063                 : //static
    3064                 : void
    3065               0 : nsJSContext::ShrinkGCBuffersNow()
    3066                 : {
    3067                 :   NS_TIME_FUNCTION_MIN(1.0);
    3068               0 :   SAMPLE_LABEL("GC", "ShrinkGCBuffersNow");
    3069                 : 
    3070               0 :   KillShrinkGCBuffersTimer();
    3071                 : 
    3072               0 :   JS_ShrinkGCBuffers(nsJSRuntime::sRuntime);
    3073               0 : }
    3074                 : 
    3075                 : //Static
    3076                 : void
    3077              48 : nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
    3078                 :                              PRInt32 aExtraForgetSkippableCalls)
    3079                 : {
    3080              48 :   if (!NS_IsMainThread()) {
    3081               0 :     return;
    3082                 :   }
    3083                 : 
    3084              48 :   if (sCCLockedOut) {
    3085                 :     // We're in the middle of an incremental GC; finish it first
    3086               0 :     nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
    3087                 :   }
    3088                 : 
    3089              96 :   SAMPLE_LABEL("GC", "CycleCollectNow");
    3090                 :   NS_TIME_FUNCTION_MIN(1.0);
    3091                 : 
    3092              48 :   KillCCTimer();
    3093                 : 
    3094              48 :   PRTime start = PR_Now();
    3095                 : 
    3096              48 :   PRUint32 suspected = nsCycleCollector_suspectedCount();
    3097                 : 
    3098              48 :   for (PRInt32 i = 0; i < aExtraForgetSkippableCalls; ++i) {
    3099               0 :     nsCycleCollector_forgetSkippable();
    3100                 :   }
    3101                 : 
    3102                 :   // nsCycleCollector_forgetSkippable may mark some gray js to black.
    3103              48 :   if (!sCleanupSinceLastGC && aExtraForgetSkippableCalls >= 0) {
    3104               0 :     nsCycleCollector_forgetSkippable();
    3105                 :   }
    3106              48 :   nsCycleCollectorResults ccResults;
    3107              48 :   nsCycleCollector_collect(&ccResults, aListener);
    3108              48 :   sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed;
    3109                 : 
    3110                 :   // If we collected a substantial amount of cycles, poke the GC since more objects
    3111                 :   // might be unreachable now.
    3112              48 :   if (sCCollectedWaitingForGC > 250) {
    3113              16 :     PokeGC(js::gcreason::CC_WAITING);
    3114                 :   }
    3115                 : 
    3116              48 :   PRTime now = PR_Now();
    3117                 : 
    3118              48 :   if (sLastCCEndTime) {
    3119               8 :     PRUint32 timeBetween = (PRUint32)(start - sLastCCEndTime) / PR_USEC_PER_SEC;
    3120               8 :     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
    3121                 :   }
    3122              48 :   sLastCCEndTime = now;
    3123                 : 
    3124                 :   Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
    3125              48 :                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC);
    3126                 : 
    3127              48 :   if (sPostGCEventsToConsole) {
    3128               0 :     PRTime delta = 0;
    3129               0 :     if (sFirstCollectionTime) {
    3130               0 :       delta = now - sFirstCollectionTime;
    3131                 :     } else {
    3132               0 :       sFirstCollectionTime = now;
    3133                 :     }
    3134                 : 
    3135               0 :     nsString gcmsg;
    3136               0 :     if (ccResults.mForcedGC) {
    3137               0 :       gcmsg.AssignLiteral(", forced a GC");
    3138                 :     }
    3139                 : 
    3140               0 :     NS_NAMED_MULTILINE_LITERAL_STRING(kFmt,
    3141                 :       NS_LL("CC(T+%.1f) duration: %llums, suspected: %lu, visited: %lu RCed and %lu GCed, collected: %lu RCed and %lu GCed (%lu waiting for GC)%s\n")
    3142                 :       NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, removed: %lu"));
    3143               0 :     nsString msg;
    3144               0 :     PRUint32 cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1;
    3145                 :     sMinForgetSkippableTime = (sMinForgetSkippableTime == PR_UINT32_MAX)
    3146               0 :       ? 0 : sMinForgetSkippableTime;
    3147                 :     msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC,
    3148                 :                                         (now - start) / PR_USEC_PER_MSEC, suspected,
    3149                 :                                         ccResults.mVisitedRefCounted, ccResults.mVisitedGCed,
    3150                 :                                         ccResults.mFreedRefCounted, ccResults.mFreedGCed,
    3151                 :                                         sCCollectedWaitingForGC, gcmsg.get(),
    3152                 :                                         sForgetSkippableBeforeCC,
    3153                 :                                         sMinForgetSkippableTime / PR_USEC_PER_MSEC,
    3154                 :                                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
    3155                 :                                         (sTotalForgetSkippableTime / cleanups) /
    3156                 :                                           PR_USEC_PER_MSEC,
    3157                 :                                         sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
    3158               0 :                                         sRemovedPurples));
    3159                 :     nsCOMPtr<nsIConsoleService> cs =
    3160               0 :       do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    3161               0 :     if (cs) {
    3162               0 :       cs->LogStringMessage(msg.get());
    3163                 :     }
    3164                 :   }
    3165              48 :   sMinForgetSkippableTime = PR_UINT32_MAX;
    3166              48 :   sMaxForgetSkippableTime = 0;
    3167              48 :   sTotalForgetSkippableTime = 0;
    3168              48 :   sRemovedPurples = 0;
    3169              48 :   sForgetSkippableBeforeCC = 0;
    3170              48 :   sCleanupSinceLastGC = true;
    3171              48 :   sNeedsFullCC = false;
    3172                 : }
    3173                 : 
    3174                 : // static
    3175                 : void
    3176               4 : GCTimerFired(nsITimer *aTimer, void *aClosure)
    3177                 : {
    3178               4 :   NS_RELEASE(sGCTimer);
    3179                 : 
    3180               4 :   uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
    3181               4 :   nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCIncremental);
    3182               4 : }
    3183                 : 
    3184                 : void
    3185               0 : ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
    3186                 : {
    3187               0 :   NS_RELEASE(sShrinkGCBuffersTimer);
    3188                 : 
    3189               0 :   nsJSContext::ShrinkGCBuffersNow();
    3190               0 : }
    3191                 : 
    3192                 : static bool
    3193             146 : ShouldTriggerCC(PRUint32 aSuspected)
    3194                 : {
    3195                 :   return sNeedsFullCC ||
    3196                 :          aSuspected > NS_CC_PURPLE_LIMIT ||
    3197             146 :          sLastCCEndTime + NS_CC_FORCED < PR_Now();
    3198                 : }
    3199                 : 
    3200                 : static void
    3201             276 : TimerFireForgetSkippable(PRUint32 aSuspected, bool aRemoveChildless)
    3202                 : {
    3203             276 :   PRTime startTime = PR_Now();
    3204             276 :   nsCycleCollector_forgetSkippable(aRemoveChildless);
    3205             276 :   sPreviousSuspectedCount = nsCycleCollector_suspectedCount();
    3206             276 :   sCleanupSinceLastGC = true;
    3207             276 :   PRTime delta = PR_Now() - startTime;
    3208             276 :   if (sMinForgetSkippableTime > delta) {
    3209             153 :     sMinForgetSkippableTime = delta;
    3210                 :   }
    3211             276 :   if (sMaxForgetSkippableTime < delta) {
    3212             167 :     sMaxForgetSkippableTime = delta;
    3213                 :   }
    3214             276 :   sTotalForgetSkippableTime += delta;
    3215             276 :   sRemovedPurples += (aSuspected - sPreviousSuspectedCount);
    3216             276 :   ++sForgetSkippableBeforeCC;
    3217             276 : }
    3218                 : 
    3219                 : static void
    3220            1740 : CCTimerFired(nsITimer *aTimer, void *aClosure)
    3221                 : {
    3222            1740 :   if (sDidShutdown) {
    3223               0 :     return;
    3224                 :   }
    3225                 : 
    3226            1740 :   if (sCCLockedOut) {
    3227               0 :     PRTime now = PR_Now();
    3228               0 :     if (sCCLockedOutTime == 0) {
    3229               0 :       sCCLockedOutTime = now;
    3230               0 :       return;
    3231                 :     }
    3232               0 :     if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
    3233               0 :       return;
    3234                 :     }
    3235                 : 
    3236                 :     // Finish the current incremental GC
    3237               0 :     nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
    3238                 :   }
    3239                 : 
    3240            1740 :   ++sCCTimerFireCount;
    3241                 : 
    3242                 :   // During early timer fires, we only run forgetSkippable. During the first
    3243                 :   // late timer fire, we decide if we are going to have a second and final
    3244                 :   // late timer fire, where we may run the CC.
    3245            1740 :   const PRUint32 numEarlyTimerFires = NS_CC_DELAY / NS_CC_SKIPPABLE_DELAY - 2;
    3246            1740 :   bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires;
    3247            1740 :   PRUint32 suspected = nsCycleCollector_suspectedCount();
    3248            1740 :   if (isLateTimerFire && ShouldTriggerCC(suspected)) {
    3249              97 :     if (sCCTimerFireCount == numEarlyTimerFires + 1) {
    3250              49 :       TimerFireForgetSkippable(suspected, true);
    3251              49 :       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
    3252                 :         // Our efforts to avoid a CC have failed, so we return to let the
    3253                 :         // timer fire once more to trigger a CC.
    3254              49 :         return;
    3255                 :       }
    3256                 :     } else {
    3257                 :       // We are in the final timer fire and still meet the conditions for
    3258                 :       // triggering a CC.
    3259              48 :       nsJSContext::CycleCollectNow();
    3260                 :     }
    3261            1643 :   } else if ((sPreviousSuspectedCount + 100) <= suspected) {
    3262                 :     // Only do a forget skippable if there are more than a few new objects.
    3263             227 :     TimerFireForgetSkippable(suspected, false);
    3264                 :   }
    3265                 : 
    3266            1691 :   if (isLateTimerFire) {
    3267                 :     // We have either just run the CC or decided we don't want to run the CC
    3268                 :     // next time, so kill the timer.
    3269              48 :     sPreviousSuspectedCount = 0;
    3270              48 :     nsJSContext::KillCCTimer();
    3271                 :   }
    3272                 : }
    3273                 : 
    3274                 : // static
    3275                 : bool
    3276             323 : nsJSContext::CleanupSinceLastGC()
    3277                 : {
    3278             323 :   return sCleanupSinceLastGC;
    3279                 : }
    3280                 : 
    3281                 : // static
    3282                 : void
    3283               0 : nsJSContext::LoadStart()
    3284                 : {
    3285               0 :   sLoadingInProgress = true;
    3286               0 :   ++sPendingLoadCount;
    3287               0 : }
    3288                 : 
    3289                 : // static
    3290                 : void
    3291               0 : nsJSContext::LoadEnd()
    3292                 : {
    3293               0 :   if (!sLoadingInProgress)
    3294               0 :     return;
    3295                 : 
    3296                 :   // sPendingLoadCount is not a well managed load counter (and doesn't
    3297                 :   // need to be), so make sure we don't make it wrap backwards here.
    3298               0 :   if (sPendingLoadCount > 0) {
    3299               0 :     --sPendingLoadCount;
    3300               0 :     return;
    3301                 :   }
    3302                 : 
    3303                 :   // Its probably a good idea to GC soon since we have finished loading.
    3304               0 :   sLoadingInProgress = false;
    3305               0 :   PokeGC(js::gcreason::LOAD_END);
    3306                 : }
    3307                 : 
    3308                 : // static
    3309                 : void
    3310              16 : nsJSContext::PokeGC(js::gcreason::Reason aReason, int aDelay)
    3311                 : {
    3312              16 :   if (sGCTimer) {
    3313                 :     // There's already a timer for GC'ing, just return
    3314               6 :     return;
    3315                 :   }
    3316                 : 
    3317              10 :   CallCreateInstance("@mozilla.org/timer;1", &sGCTimer);
    3318                 : 
    3319              10 :   if (!sGCTimer) {
    3320                 :     // Failed to create timer (probably because we're in XPCOM shutdown)
    3321               0 :     return;
    3322                 :   }
    3323                 : 
    3324                 :   static bool first = true;
    3325                 : 
    3326                 :   sGCTimer->InitWithFuncCallback(GCTimerFired, reinterpret_cast<void *>(aReason),
    3327                 :                                  aDelay
    3328                 :                                  ? aDelay
    3329                 :                                  : (first
    3330                 :                                     ? NS_FIRST_GC_DELAY
    3331                 :                                     : NS_GC_DELAY),
    3332              10 :                                  nsITimer::TYPE_ONE_SHOT);
    3333                 : 
    3334              10 :   first = false;
    3335                 : }
    3336                 : 
    3337                 : // static
    3338                 : void
    3339             398 : nsJSContext::PokeShrinkGCBuffers()
    3340                 : {
    3341             398 :   if (sShrinkGCBuffersTimer) {
    3342               0 :     return;
    3343                 :   }
    3344                 : 
    3345             398 :   CallCreateInstance("@mozilla.org/timer;1", &sShrinkGCBuffersTimer);
    3346                 : 
    3347             398 :   if (!sShrinkGCBuffersTimer) {
    3348                 :     // Failed to create timer (probably because we're in XPCOM shutdown)
    3349             248 :     return;
    3350                 :   }
    3351                 : 
    3352                 :   sShrinkGCBuffersTimer->InitWithFuncCallback(ShrinkGCBuffersTimerFired, nsnull,
    3353                 :                                               NS_SHRINK_GC_BUFFERS_DELAY,
    3354             150 :                                               nsITimer::TYPE_ONE_SHOT);
    3355                 : }
    3356                 : 
    3357                 : // static
    3358                 : void
    3359          174926 : nsJSContext::MaybePokeCC()
    3360                 : {
    3361          174926 :   if (sCCTimer || sDidShutdown) {
    3362          153788 :     return;
    3363                 :   }
    3364                 : 
    3365           63366 :   if (sNeedsFullCC ||
    3366           21138 :       nsCycleCollector_suspectedCount() > 100 ||
    3367           21090 :       sLastCCEndTime + NS_CC_FORCED < PR_Now()) {
    3368            1041 :     sCCTimerFireCount = 0;
    3369            1041 :     CallCreateInstance("@mozilla.org/timer;1", &sCCTimer);
    3370            1041 :     if (!sCCTimer) {
    3371               0 :       return;
    3372                 :     }
    3373                 :     sCCTimer->InitWithFuncCallback(CCTimerFired, nsnull,
    3374                 :                                    NS_CC_SKIPPABLE_DELAY,
    3375            1041 :                                    nsITimer::TYPE_REPEATING_SLACK);
    3376                 :   }
    3377                 : }
    3378                 : 
    3379                 : //static
    3380                 : void
    3381            1805 : nsJSContext::KillGCTimer()
    3382                 : {
    3383            1805 :   if (sGCTimer) {
    3384               6 :     sGCTimer->Cancel();
    3385                 : 
    3386               6 :     NS_RELEASE(sGCTimer);
    3387                 :   }
    3388            1805 : }
    3389                 : 
    3390                 : //static
    3391                 : void
    3392            1805 : nsJSContext::KillShrinkGCBuffersTimer()
    3393                 : {
    3394            1805 :   if (sShrinkGCBuffersTimer) {
    3395             150 :     sShrinkGCBuffersTimer->Cancel();
    3396                 : 
    3397             150 :     NS_RELEASE(sShrinkGCBuffersTimer);
    3398                 :   }
    3399            1805 : }
    3400                 : 
    3401                 : //static
    3402                 : void
    3403            1499 : nsJSContext::KillCCTimer()
    3404                 : {
    3405            1499 :   sCCLockedOutTime = 0;
    3406                 : 
    3407            1499 :   if (sCCTimer) {
    3408            1040 :     sCCTimer->Cancel();
    3409                 : 
    3410            1040 :     NS_RELEASE(sCCTimer);
    3411                 :   }
    3412            1499 : }
    3413                 : 
    3414                 : void
    3415               0 : nsJSContext::GC(js::gcreason::Reason aReason)
    3416                 : {
    3417               0 :   PokeGC(aReason);
    3418               0 : }
    3419                 : 
    3420                 : static void
    3421             796 : DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescription &aDesc)
    3422                 : {
    3423             796 :   NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
    3424                 : 
    3425             796 :   if (aDesc.logMessage && sPostGCEventsToConsole) {
    3426               0 :     PRTime now = PR_Now();
    3427               0 :     PRTime delta = 0;
    3428               0 :     if (sFirstCollectionTime) {
    3429               0 :       delta = now - sFirstCollectionTime;
    3430                 :     } else {
    3431               0 :       sFirstCollectionTime = now;
    3432                 :     }
    3433                 : 
    3434               0 :     NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f) %s");
    3435               0 :     nsString msg;
    3436                 :     msg.Adopt(nsTextFormatter::smprintf(kFmt.get(),
    3437                 :                                         double(delta) / PR_USEC_PER_SEC,
    3438               0 :                                         aDesc.logMessage));
    3439               0 :     nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    3440               0 :     if (cs) {
    3441               0 :       cs->LogStringMessage(msg.get());
    3442                 :     }
    3443                 :   }
    3444                 : 
    3445                 :   // Prevent cycle collections and shrinking during incremental GC.
    3446             796 :   if (aProgress == js::GC_CYCLE_BEGIN) {
    3447             398 :     sCCLockedOut = true;
    3448             398 :     nsJSContext::KillShrinkGCBuffersTimer();
    3449             398 :   } else if (aProgress == js::GC_CYCLE_END) {
    3450             398 :     sCCLockedOut = false;
    3451                 :   }
    3452                 : 
    3453                 :   // The GC has more work to do, so schedule another GC slice.
    3454             796 :   if (aProgress == js::GC_SLICE_END) {
    3455               0 :     nsJSContext::KillGCTimer();
    3456               0 :     nsJSContext::PokeGC(js::gcreason::INTER_SLICE_GC, NS_INTERSLICE_GC_DELAY);
    3457                 :   }
    3458                 : 
    3459             796 :   if (aProgress == js::GC_CYCLE_END) {
    3460                 :     // May need to kill the inter-slice GC timer
    3461             398 :     nsJSContext::KillGCTimer();
    3462                 : 
    3463             398 :     sCCollectedWaitingForGC = 0;
    3464             398 :     sCleanupSinceLastGC = false;
    3465                 : 
    3466             398 :     if (aDesc.isCompartment) {
    3467                 :       // If this is a compartment GC, restart it. We still want
    3468                 :       // a full GC to happen. Compartment GCs usually happen as a
    3469                 :       // result of last-ditch or MaybeGC. In both cases it is
    3470                 :       // probably a time of heavy activity and we want to delay
    3471                 :       // the full GC, but we do want it to happen eventually.
    3472               0 :       nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
    3473                 :     }
    3474                 : 
    3475             398 :     sNeedsFullCC = true;
    3476             398 :     nsJSContext::MaybePokeCC();
    3477                 : 
    3478             398 :     if (!aDesc.isCompartment) {
    3479                 :       // Avoid shrinking during heavy activity, which is suggested by
    3480                 :       // compartment GC.
    3481             398 :       nsJSContext::PokeShrinkGCBuffers();
    3482                 :     }
    3483                 :   }
    3484                 : 
    3485             796 :   if (sPrevGCSliceCallback)
    3486               0 :     (*sPrevGCSliceCallback)(aRt, aProgress, aDesc);
    3487             796 : }
    3488                 : 
    3489                 : // Script object mananagement - note duplicate implementation
    3490                 : // in nsJSRuntime below...
    3491                 : nsresult
    3492               0 : nsJSContext::HoldScriptObject(void* aScriptObject)
    3493                 : {
    3494               0 :     NS_ASSERTION(sIsInitialized, "runtime not initialized");
    3495               0 :     if (! nsJSRuntime::sRuntime) {
    3496               0 :         NS_NOTREACHED("couldn't add GC root - no runtime");
    3497               0 :         return NS_ERROR_FAILURE;
    3498                 :     }
    3499                 : 
    3500               0 :     ::JS_LockGCThingRT(nsJSRuntime::sRuntime, aScriptObject);
    3501               0 :     return NS_OK;
    3502                 : }
    3503                 : 
    3504                 : nsresult
    3505               0 : nsJSContext::DropScriptObject(void* aScriptObject)
    3506                 : {
    3507               0 :   NS_ASSERTION(sIsInitialized, "runtime not initialized");
    3508               0 :   if (! nsJSRuntime::sRuntime) {
    3509               0 :     NS_NOTREACHED("couldn't remove GC root");
    3510               0 :     return NS_ERROR_FAILURE;
    3511                 :   }
    3512                 : 
    3513               0 :   ::JS_UnlockGCThingRT(nsJSRuntime::sRuntime, aScriptObject);
    3514               0 :   return NS_OK;
    3515                 : }
    3516                 : 
    3517                 : void
    3518               0 : nsJSContext::ReportPendingException()
    3519                 : {
    3520                 :   // set aside the frame chain, since it has nothing to do with the
    3521                 :   // exception we're reporting.
    3522               0 :   if (mIsInitialized && ::JS_IsExceptionPending(mContext)) {
    3523               0 :     bool saved = ::JS_SaveFrameChain(mContext);
    3524               0 :     ::JS_ReportPendingException(mContext);
    3525               0 :     if (saved)
    3526               0 :         ::JS_RestoreFrameChain(mContext);
    3527                 :   }
    3528               0 : }
    3529                 : 
    3530                 : /**********************************************************************
    3531                 :  * nsJSRuntime implementation
    3532                 :  *********************************************************************/
    3533                 : 
    3534                 : // QueryInterface implementation for nsJSRuntime
    3535              50 : NS_INTERFACE_MAP_BEGIN(nsJSRuntime)
    3536              50 :   NS_INTERFACE_MAP_ENTRY(nsIScriptRuntime)
    3537               0 : NS_INTERFACE_MAP_END
    3538                 : 
    3539                 : 
    3540             100 : NS_IMPL_ADDREF(nsJSRuntime)
    3541             150 : NS_IMPL_RELEASE(nsJSRuntime)
    3542                 : 
    3543                 : already_AddRefed<nsIScriptContext>
    3544               0 : nsJSRuntime::CreateContext()
    3545                 : {
    3546               0 :   nsCOMPtr<nsIScriptContext> scriptContext = new nsJSContext(sRuntime);
    3547               0 :   return scriptContext.forget();
    3548                 : }
    3549                 : 
    3550                 : nsresult
    3551               0 : nsJSRuntime::ParseVersion(const nsString &aVersionStr, PRUint32 *flags)
    3552                 : {
    3553               0 :     NS_PRECONDITION(flags, "Null flags param?");
    3554               0 :     JSVersion jsVersion = JSVERSION_UNKNOWN;
    3555               0 :     if (aVersionStr.Length() != 3 || aVersionStr[0] != '1' || aVersionStr[1] != '.')
    3556               0 :         jsVersion = JSVERSION_UNKNOWN;
    3557               0 :     else switch (aVersionStr[2]) {
    3558               0 :         case '0': jsVersion = JSVERSION_1_0; break;
    3559               0 :         case '1': jsVersion = JSVERSION_1_1; break;
    3560               0 :         case '2': jsVersion = JSVERSION_1_2; break;
    3561               0 :         case '3': jsVersion = JSVERSION_1_3; break;
    3562               0 :         case '4': jsVersion = JSVERSION_1_4; break;
    3563               0 :         case '5': jsVersion = JSVERSION_1_5; break;
    3564               0 :         case '6': jsVersion = JSVERSION_1_6; break;
    3565               0 :         case '7': jsVersion = JSVERSION_1_7; break;
    3566               0 :         case '8': jsVersion = JSVERSION_1_8; break;
    3567               0 :         default:  jsVersion = JSVERSION_UNKNOWN;
    3568                 :     }
    3569               0 :     *flags = (PRUint32)jsVersion;
    3570               0 :     return NS_OK;
    3571                 : }
    3572                 : 
    3573                 : //static
    3574                 : void
    3575            1404 : nsJSRuntime::Startup()
    3576                 : {
    3577                 :   // initialize all our statics, so that we can restart XPCOM
    3578            1404 :   sGCTimer = sCCTimer = nsnull;
    3579            1404 :   sCCLockedOut = false;
    3580            1404 :   sCCLockedOutTime = 0;
    3581            1404 :   sLastCCEndTime = 0;
    3582            1404 :   sPendingLoadCount = 0;
    3583            1404 :   sLoadingInProgress = false;
    3584            1404 :   sCCollectedWaitingForGC = 0;
    3585            1404 :   sPostGCEventsToConsole = false;
    3586            1404 :   sNeedsFullCC = false;
    3587            1404 :   gNameSpaceManager = nsnull;
    3588            1404 :   sRuntimeService = nsnull;
    3589            1404 :   sRuntime = nsnull;
    3590            1404 :   sIsInitialized = false;
    3591            1404 :   sDidShutdown = false;
    3592            1404 :   sContextCount = 0;
    3593            1404 :   sSecurityManager = nsnull;
    3594            1404 : }
    3595                 : 
    3596                 : static int
    3597             100 : MaxScriptRunTimePrefChangedCallback(const char *aPrefName, void *aClosure)
    3598                 : {
    3599                 :   // Default limit on script run time to 10 seconds. 0 means let
    3600                 :   // scripts run forever.
    3601                 :   bool isChromePref =
    3602             100 :     strcmp(aPrefName, "dom.max_chrome_script_run_time") == 0;
    3603             100 :   PRInt32 time = Preferences::GetInt(aPrefName, isChromePref ? 20 : 10);
    3604                 : 
    3605                 :   PRTime t;
    3606             100 :   if (time <= 0) {
    3607                 :     // Let scripts run for a really, really long time.
    3608               0 :     t = LL_INIT(0x40000000, 0);
    3609                 :   } else {
    3610             100 :     t = time * PR_USEC_PER_SEC;
    3611                 :   }
    3612                 : 
    3613             100 :   if (isChromePref) {
    3614              50 :     sMaxChromeScriptRunTime = t;
    3615                 :   } else {
    3616              50 :     sMaxScriptRunTime = t;
    3617                 :   }
    3618                 : 
    3619             100 :   return 0;
    3620                 : }
    3621                 : 
    3622                 : static int
    3623              50 : ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName, void* aClosure)
    3624                 : {
    3625              50 :   bool reportAll = Preferences::GetBool(aPrefName, false);
    3626              50 :   nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll);
    3627              50 :   return 0;
    3628                 : }
    3629                 : 
    3630                 : static int
    3631              50 : SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName, void* aClosure)
    3632                 : {
    3633              50 :   PRInt32 highwatermark = Preferences::GetInt(aPrefName, 128);
    3634                 : 
    3635                 :   JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_MALLOC_BYTES,
    3636              50 :                     highwatermark * 1024L * 1024L);
    3637              50 :   return 0;
    3638                 : }
    3639                 : 
    3640                 : static int
    3641              50 : SetMemoryMaxPrefChangedCallback(const char* aPrefName, void* aClosure)
    3642                 : {
    3643              50 :   PRInt32 pref = Preferences::GetInt(aPrefName, -1);
    3644                 :   // handle overflow and negative pref values
    3645              50 :   PRUint32 max = (pref <= 0 || pref >= 0x1000) ? -1 : (PRUint32)pref * 1024 * 1024;
    3646              50 :   JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_BYTES, max);
    3647              50 :   return 0;
    3648                 : }
    3649                 : 
    3650                 : static int
    3651             100 : SetMemoryGCModePrefChangedCallback(const char* aPrefName, void* aClosure)
    3652                 : {
    3653             100 :   PRBool enableCompartmentGC = Preferences::GetBool("javascript.options.mem.gc_per_compartment");
    3654             100 :   PRBool enableIncrementalGC = Preferences::GetBool("javascript.options.mem.gc_incremental");
    3655                 :   JSGCMode mode;
    3656             100 :   if (enableIncrementalGC) {
    3657               0 :     mode = JSGC_MODE_INCREMENTAL;
    3658             100 :   } else if (enableCompartmentGC) {
    3659             100 :     mode = JSGC_MODE_COMPARTMENT;
    3660                 :   } else {
    3661               0 :     mode = JSGC_MODE_GLOBAL;
    3662                 :   }
    3663             100 :   JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MODE, mode);
    3664             100 :   return 0;
    3665                 : }
    3666                 : 
    3667                 : static int
    3668              50 : SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName, void* aClosure)
    3669                 : {
    3670              50 :   PRInt32 pref = Preferences::GetInt(aPrefName, -1);
    3671                 :   // handle overflow and negative pref values
    3672              50 :   if (pref > 0 && pref < 100000)
    3673              50 :     JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_SLICE_TIME_BUDGET, pref);
    3674              50 :   return 0;
    3675                 : }
    3676                 : 
    3677                 : JSObject*
    3678               0 : NS_DOMReadStructuredClone(JSContext* cx,
    3679                 :                           JSStructuredCloneReader* reader,
    3680                 :                           uint32_t tag,
    3681                 :                           uint32_t data,
    3682                 :                           void* closure)
    3683                 : {
    3684                 :   // We don't currently support any extensions to structured cloning.
    3685               0 :   nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
    3686               0 :   return nsnull;
    3687                 : }
    3688                 : 
    3689                 : JSBool
    3690               0 : NS_DOMWriteStructuredClone(JSContext* cx,
    3691                 :                            JSStructuredCloneWriter* writer,
    3692                 :                            JSObject* obj,
    3693                 :                            void *closure)
    3694                 : {
    3695                 :   // We don't currently support any extensions to structured cloning.
    3696               0 :   nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
    3697               0 :   return JS_FALSE;
    3698                 : }
    3699                 : 
    3700                 : void
    3701               0 : NS_DOMStructuredCloneError(JSContext* cx,
    3702                 :                            uint32_t errorid)
    3703                 : {
    3704                 :   // We don't currently support any extensions to structured cloning.
    3705               0 :   nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
    3706               0 : }
    3707                 : 
    3708                 : //static
    3709                 : nsresult
    3710              50 : nsJSRuntime::Init()
    3711                 : {
    3712              50 :   if (sIsInitialized) {
    3713               0 :     if (!nsContentUtils::XPConnect())
    3714               0 :       return NS_ERROR_NOT_AVAILABLE;
    3715                 : 
    3716               0 :     return NS_OK;
    3717                 :   }
    3718                 : 
    3719                 :   nsresult rv = CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID,
    3720              50 :                                &sSecurityManager);
    3721              50 :   NS_ENSURE_SUCCESS(rv, rv);
    3722                 : 
    3723              50 :   rv = CallGetService(kJSRuntimeServiceContractID, &sRuntimeService);
    3724                 :   // get the JSRuntime from the runtime svc, if possible
    3725              50 :   NS_ENSURE_SUCCESS(rv, rv);
    3726                 : 
    3727              50 :   rv = sRuntimeService->GetRuntime(&sRuntime);
    3728              50 :   NS_ENSURE_SUCCESS(rv, rv);
    3729                 : 
    3730                 :   // Let's make sure that our main thread is the same as the xpcom main thread.
    3731              50 :   NS_ASSERTION(NS_IsMainThread(), "bad");
    3732                 : 
    3733              50 :   sPrevGCSliceCallback = js::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
    3734                 : 
    3735                 :   // Set up the structured clone callbacks.
    3736                 :   static JSStructuredCloneCallbacks cloneCallbacks = {
    3737                 :     NS_DOMReadStructuredClone,
    3738                 :     NS_DOMWriteStructuredClone,
    3739                 :     NS_DOMStructuredCloneError
    3740                 :   };
    3741              50 :   JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks);
    3742                 : 
    3743                 :   // Set these global xpconnect options...
    3744                 :   Preferences::RegisterCallback(MaxScriptRunTimePrefChangedCallback,
    3745              50 :                                 "dom.max_script_run_time");
    3746              50 :   MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull);
    3747                 : 
    3748                 :   Preferences::RegisterCallback(MaxScriptRunTimePrefChangedCallback,
    3749              50 :                                 "dom.max_chrome_script_run_time");
    3750                 :   MaxScriptRunTimePrefChangedCallback("dom.max_chrome_script_run_time",
    3751              50 :                                       nsnull);
    3752                 : 
    3753                 :   Preferences::RegisterCallback(ReportAllJSExceptionsPrefChangedCallback,
    3754              50 :                                 "dom.report_all_js_exceptions");
    3755                 :   ReportAllJSExceptionsPrefChangedCallback("dom.report_all_js_exceptions",
    3756              50 :                                            nsnull);
    3757                 : 
    3758                 :   Preferences::RegisterCallback(SetMemoryHighWaterMarkPrefChangedCallback,
    3759              50 :                                 "javascript.options.mem.high_water_mark");
    3760                 :   SetMemoryHighWaterMarkPrefChangedCallback("javascript.options.mem.high_water_mark",
    3761              50 :                                             nsnull);
    3762                 : 
    3763                 :   Preferences::RegisterCallback(SetMemoryMaxPrefChangedCallback,
    3764              50 :                                 "javascript.options.mem.max");
    3765                 :   SetMemoryMaxPrefChangedCallback("javascript.options.mem.max",
    3766              50 :                                   nsnull);
    3767                 : 
    3768                 :   Preferences::RegisterCallback(SetMemoryGCModePrefChangedCallback,
    3769              50 :                                 "javascript.options.mem.gc_per_compartment");
    3770                 :   SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_per_compartment",
    3771              50 :                                      nsnull);
    3772                 : 
    3773                 :   Preferences::RegisterCallback(SetMemoryGCModePrefChangedCallback,
    3774              50 :                                 "javascript.options.mem.gc_incremental");
    3775                 :   SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_incremental",
    3776              50 :                                      nsnull);
    3777                 : 
    3778                 :   Preferences::RegisterCallback(SetMemoryGCSliceTimePrefChangedCallback,
    3779              50 :                                 "javascript.options.mem.gc_incremental_slice_ms");
    3780                 :   SetMemoryGCSliceTimePrefChangedCallback("javascript.options.mem.gc_incremental_slice_ms",
    3781              50 :                                           nsnull);
    3782                 : 
    3783             100 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    3784              50 :   if (!obs)
    3785               0 :     return NS_ERROR_FAILURE;
    3786                 : 
    3787                 :   Preferences::AddBoolVarCache(&sGCOnMemoryPressure,
    3788                 :                                "javascript.options.gc_on_memory_pressure",
    3789              50 :                                true);
    3790                 : 
    3791              50 :   nsIObserver* memPressureObserver = new nsMemoryPressureObserver();
    3792              50 :   NS_ENSURE_TRUE(memPressureObserver, NS_ERROR_OUT_OF_MEMORY);
    3793              50 :   obs->AddObserver(memPressureObserver, "memory-pressure", false);
    3794                 : 
    3795              50 :   sIsInitialized = true;
    3796                 : 
    3797              50 :   return NS_OK;
    3798                 : }
    3799                 : 
    3800                 : //static
    3801                 : nsScriptNameSpaceManager*
    3802          231336 : nsJSRuntime::GetNameSpaceManager()
    3803                 : {
    3804          231336 :   if (sDidShutdown)
    3805               0 :     return nsnull;
    3806                 : 
    3807          231336 :   if (!gNameSpaceManager) {
    3808             306 :     gNameSpaceManager = new nsScriptNameSpaceManager;
    3809             306 :     NS_ADDREF(gNameSpaceManager);
    3810                 : 
    3811             306 :     nsresult rv = gNameSpaceManager->Init();
    3812             306 :     NS_ENSURE_SUCCESS(rv, nsnull);
    3813                 :   }
    3814                 : 
    3815          231336 :   return gNameSpaceManager;
    3816                 : }
    3817                 : 
    3818                 : /* static */
    3819                 : void
    3820            1403 : nsJSRuntime::Shutdown()
    3821                 : {
    3822            1403 :   nsJSContext::KillGCTimer();
    3823            1403 :   nsJSContext::KillShrinkGCBuffersTimer();
    3824            1403 :   nsJSContext::KillCCTimer();
    3825                 : 
    3826            1403 :   NS_IF_RELEASE(gNameSpaceManager);
    3827                 : 
    3828            1403 :   if (!sContextCount) {
    3829                 :     // We're being shutdown, and there are no more contexts
    3830                 :     // alive, release the JS runtime service and the security manager.
    3831                 : 
    3832            1403 :     NS_IF_RELEASE(sRuntimeService);
    3833            1403 :     NS_IF_RELEASE(sSecurityManager);
    3834                 :   }
    3835                 : 
    3836            1403 :   sDidShutdown = true;
    3837            1403 : }
    3838                 : 
    3839                 : // Script object mananagement - note duplicate implementation
    3840                 : // in nsJSContext above...
    3841                 : nsresult
    3842               0 : nsJSRuntime::HoldScriptObject(void* aScriptObject)
    3843                 : {
    3844               0 :     NS_ASSERTION(sIsInitialized, "runtime not initialized");
    3845               0 :     if (! sRuntime) {
    3846               0 :         NS_NOTREACHED("couldn't remove GC root - no runtime");
    3847               0 :         return NS_ERROR_FAILURE;
    3848                 :     }
    3849                 : 
    3850               0 :     ::JS_LockGCThingRT(sRuntime, aScriptObject);
    3851               0 :     return NS_OK;
    3852                 : }
    3853                 : 
    3854                 : nsresult
    3855               0 : nsJSRuntime::DropScriptObject(void* aScriptObject)
    3856                 : {
    3857               0 :   NS_ASSERTION(sIsInitialized, "runtime not initialized");
    3858               0 :   if (! sRuntime) {
    3859               0 :     NS_NOTREACHED("couldn't remove GC root");
    3860               0 :     return NS_ERROR_FAILURE;
    3861                 :   }
    3862                 : 
    3863               0 :   ::JS_UnlockGCThingRT(sRuntime, aScriptObject);
    3864               0 :   return NS_OK;
    3865                 : }
    3866                 : 
    3867                 : // A factory for the runtime.
    3868              50 : nsresult NS_CreateJSRuntime(nsIScriptRuntime **aRuntime)
    3869                 : {
    3870              50 :   nsresult rv = nsJSRuntime::Init();
    3871              50 :   NS_ENSURE_SUCCESS(rv, rv);
    3872                 : 
    3873              50 :   *aRuntime = new nsJSRuntime();
    3874              50 :   if (*aRuntime == nsnull)
    3875               0 :     return NS_ERROR_OUT_OF_MEMORY;
    3876              50 :   NS_IF_ADDREF(*aRuntime);
    3877              50 :   return NS_OK;
    3878                 : }
    3879                 : 
    3880                 : // A fast-array class for JS.  This class supports both nsIJSScriptArray and
    3881                 : // nsIArray.  If it is JS itself providing and consuming this class, all work
    3882                 : // can be done via nsIJSScriptArray, and avoid the conversion of elements
    3883                 : // to/from nsISupports.
    3884                 : // When consumed by non-JS (eg, another script language), conversion is done
    3885                 : // on-the-fly.
    3886                 : class nsJSArgArray : public nsIJSArgArray {
    3887                 : public:
    3888                 :   nsJSArgArray(JSContext *aContext, PRUint32 argc, jsval *argv, nsresult *prv);
    3889                 :   ~nsJSArgArray();
    3890                 :   // nsISupports
    3891               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    3892            1464 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray,
    3893                 :                                                          nsIJSArgArray)
    3894                 : 
    3895                 :   // nsIArray
    3896                 :   NS_DECL_NSIARRAY
    3897                 : 
    3898                 :   // nsIJSArgArray
    3899                 :   nsresult GetArgs(PRUint32 *argc, void **argv);
    3900                 : 
    3901                 :   void ReleaseJSObjects();
    3902                 : 
    3903                 : protected:
    3904                 :   JSContext *mContext;
    3905                 :   jsval *mArgv;
    3906                 :   PRUint32 mArgc;
    3907                 : };
    3908                 : 
    3909               0 : nsJSArgArray::nsJSArgArray(JSContext *aContext, PRUint32 argc, jsval *argv,
    3910                 :                            nsresult *prv) :
    3911                 :     mContext(aContext),
    3912                 :     mArgv(nsnull),
    3913               0 :     mArgc(argc)
    3914                 : {
    3915                 :   // copy the array - we don't know its lifetime, and ours is tied to xpcom
    3916                 :   // refcounting.  Alloc zero'd array so cleanup etc is safe.
    3917               0 :   if (argc) {
    3918               0 :     mArgv = (jsval *) PR_CALLOC(argc * sizeof(jsval));
    3919               0 :     if (!mArgv) {
    3920               0 :       *prv = NS_ERROR_OUT_OF_MEMORY;
    3921               0 :       return;
    3922                 :     }
    3923                 :   }
    3924                 : 
    3925                 :   // Callers are allowed to pass in a null argv even for argc > 0. They can
    3926                 :   // then use GetArgs to initialize the values.
    3927               0 :   if (argv) {
    3928               0 :     for (PRUint32 i = 0; i < argc; ++i)
    3929               0 :       mArgv[i] = argv[i];
    3930                 :   }
    3931                 : 
    3932               0 :   *prv = argc > 0 ? NS_HOLD_JS_OBJECTS(this, nsJSArgArray) : NS_OK;
    3933                 : }
    3934                 : 
    3935               0 : nsJSArgArray::~nsJSArgArray()
    3936                 : {
    3937               0 :   ReleaseJSObjects();
    3938               0 : }
    3939                 : 
    3940                 : void
    3941               0 : nsJSArgArray::ReleaseJSObjects()
    3942                 : {
    3943               0 :   if (mArgc > 0)
    3944               0 :     NS_DROP_JS_OBJECTS(this, nsJSArgArray);
    3945               0 :   if (mArgv) {
    3946               0 :     PR_DELETE(mArgv);
    3947                 :   }
    3948               0 :   mArgc = 0;
    3949               0 : }
    3950                 : 
    3951                 : // QueryInterface implementation for nsJSArgArray
    3952            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray)
    3953               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSArgArray)
    3954               0 :   tmp->ReleaseJSObjects();
    3955               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    3956               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray)
    3957               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    3958               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    3959                 : 
    3960               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray)
    3961               0 :   jsval *argv = tmp->mArgv;
    3962               0 :   if (argv) {
    3963                 :     jsval *end;
    3964               0 :     for (end = argv + tmp->mArgc; argv < end; ++argv) {
    3965               0 :       if (JSVAL_IS_GCTHING(*argv))
    3966               0 :         NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT,
    3967                 :                                                 JSVAL_TO_GCTHING(*argv),
    3968                 :                                                 "mArgv[i]")
    3969                 :     }
    3970                 :   }
    3971               0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    3972                 : 
    3973               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray)
    3974               0 :   NS_INTERFACE_MAP_ENTRY(nsIArray)
    3975               0 :   NS_INTERFACE_MAP_ENTRY(nsIJSArgArray)
    3976               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSArgArray)
    3977               0 : NS_INTERFACE_MAP_END
    3978                 : 
    3979               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSArgArray)
    3980               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSArgArray)
    3981                 : 
    3982                 : nsresult
    3983               0 : nsJSArgArray::GetArgs(PRUint32 *argc, void **argv)
    3984                 : {
    3985               0 :   *argv = (void *)mArgv;
    3986               0 :   *argc = mArgc;
    3987               0 :   return NS_OK;
    3988                 : }
    3989                 : 
    3990                 : // nsIArray impl
    3991               0 : NS_IMETHODIMP nsJSArgArray::GetLength(PRUint32 *aLength)
    3992                 : {
    3993               0 :   *aLength = mArgc;
    3994               0 :   return NS_OK;
    3995                 : }
    3996                 : 
    3997                 : /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
    3998               0 : NS_IMETHODIMP nsJSArgArray::QueryElementAt(PRUint32 index, const nsIID & uuid, void * *result)
    3999                 : {
    4000               0 :   *result = nsnull;
    4001               0 :   if (index >= mArgc)
    4002               0 :     return NS_ERROR_INVALID_ARG;
    4003                 : 
    4004               0 :   if (uuid.Equals(NS_GET_IID(nsIVariant)) || uuid.Equals(NS_GET_IID(nsISupports))) {
    4005               0 :     return nsContentUtils::XPConnect()->JSToVariant(mContext, mArgv[index],
    4006               0 :                                                     (nsIVariant **)result);
    4007                 :   }
    4008               0 :   NS_WARNING("nsJSArgArray only handles nsIVariant");
    4009               0 :   return NS_ERROR_NO_INTERFACE;
    4010                 : }
    4011                 : 
    4012                 : /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
    4013               0 : NS_IMETHODIMP nsJSArgArray::IndexOf(PRUint32 startIndex, nsISupports *element, PRUint32 *_retval)
    4014                 : {
    4015               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4016                 : }
    4017                 : 
    4018                 : /* nsISimpleEnumerator enumerate (); */
    4019               0 : NS_IMETHODIMP nsJSArgArray::Enumerate(nsISimpleEnumerator **_retval)
    4020                 : {
    4021               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4022                 : }
    4023                 : 
    4024                 : // The factory function
    4025               0 : nsresult NS_CreateJSArgv(JSContext *aContext, PRUint32 argc, void *argv,
    4026                 :                          nsIJSArgArray **aArray)
    4027                 : {
    4028                 :   nsresult rv;
    4029                 :   nsJSArgArray *ret = new nsJSArgArray(aContext, argc,
    4030               0 :                                        static_cast<jsval *>(argv), &rv);
    4031               0 :   if (ret == nsnull)
    4032               0 :     return NS_ERROR_OUT_OF_MEMORY;
    4033               0 :   if (NS_FAILED(rv)) {
    4034               0 :     delete ret;
    4035               0 :     return rv;
    4036                 :   }
    4037               0 :   return ret->QueryInterface(NS_GET_IID(nsIArray), (void **)aArray);
    4038            4392 : }

Generated by: LCOV version 1.7