Back to index

lightning-sunbird  0.9+nobinonly
nsJSEnvironment.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsJSEnvironment.h"
00039 #include "nsIScriptContextOwner.h"
00040 #include "nsIScriptGlobalObject.h"
00041 #include "nsIScriptObjectPrincipal.h"
00042 #include "nsIDOMChromeWindow.h"
00043 #include "nsIDOMWindowInternal.h"
00044 #include "nsIDOMNode.h"
00045 #include "nsIDOMElement.h"
00046 #include "nsIDOMDocument.h"
00047 #include "nsIDOMText.h"
00048 #include "nsIDOMAttr.h"
00049 #include "nsIDOMNamedNodeMap.h"
00050 #include "nsIDOMNodeList.h"
00051 #include "nsIDOMKeyEvent.h"
00052 #include "nsIDOMHTMLImageElement.h"
00053 #include "nsIDOMHTMLOptionElement.h"
00054 #include "nsIDOMChromeWindow.h"
00055 #include "nsIScriptSecurityManager.h"
00056 #include "nsDOMCID.h"
00057 #include "nsIServiceManager.h"
00058 #include "nsIXPConnect.h"
00059 #include "nsIJSContextStack.h"
00060 #include "nsIJSRuntimeService.h"
00061 #include "nsCOMPtr.h"
00062 #include "nsReadableUtils.h"
00063 #include "nsJSUtils.h"
00064 #include "nsIDocShell.h"
00065 #include "nsIDocShellTreeItem.h"
00066 #include "nsPresContext.h"
00067 #include "nsIConsoleService.h"
00068 #include "nsIScriptError.h"
00069 #include "nsIInterfaceRequestor.h"
00070 #include "nsIInterfaceRequestorUtils.h"
00071 #include "nsIPrompt.h"
00072 #include "nsIObserverService.h"
00073 #include "nsGUIEvent.h"
00074 #include "nsScriptNameSpaceManager.h"
00075 #include "nsIThread.h"
00076 #include "nsITimer.h"
00077 #include "nsDOMClassInfo.h"
00078 #include "nsIAtom.h"
00079 #include "nsContentUtils.h"
00080 #include "jscntxt.h"
00081 #include "jsdbgapi.h"
00082 #include "nsIDOMGCParticipant.h"
00083 #include "nsIDocument.h"
00084 #include "nsIContent.h"
00085 
00086 // For locale aware string methods
00087 #include "plstr.h"
00088 #include "nsIPlatformCharset.h"
00089 #include "nsICharsetConverterManager.h"
00090 #include "nsUnicharUtils.h"
00091 #include "nsILocaleService.h"
00092 #include "nsICollation.h"
00093 #include "nsCollationCID.h"
00094 #include "nsDOMClassInfo.h"
00095 
00096 #ifdef MOZ_JSDEBUGGER
00097 #include "jsdIDebuggerService.h"
00098 #endif
00099 
00100 static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
00101 
00102 #include "nsIStringBundle.h"
00103 
00104 #ifdef MOZ_LOGGING
00105 // Force PR_LOGGING so we can get JS strict warnings even in release builds
00106 #define FORCE_PR_LOG 1
00107 #endif
00108 #include "prlog.h"
00109 #include "prthread.h"
00110 
00111 #ifdef OJI
00112 #include "nsIJVMManager.h"
00113 #include "nsILiveConnectManager.h"
00114 #endif
00115 
00116 const size_t gStackSize = 8192;
00117 
00118 #ifdef PR_LOGGING
00119 static PRLogModuleInfo* gJSDiagnostics;
00120 #endif
00121 
00122 // Thank you Microsoft!
00123 #ifndef WINCE
00124 #ifdef CompareString
00125 #undef CompareString
00126 #endif
00127 #endif // WINCE
00128 
00129 #define NS_GC_DELAY                2000 // ms
00130 #define NS_FIRST_GC_DELAY          10000 // ms
00131 
00132 // if you add statics here, add them to the list in nsJSEnvironment::Startup
00133 
00134 static nsITimer *sGCTimer;
00135 static PRBool sReadyForGC;
00136 
00137 nsScriptNameSpaceManager *gNameSpaceManager;
00138 
00139 static nsIJSRuntimeService *sRuntimeService;
00140 JSRuntime *nsJSEnvironment::sRuntime;
00141 
00142 static const char kJSRuntimeServiceContractID[] =
00143   "@mozilla.org/js/xpc/RuntimeService;1";
00144 
00145 static const char kDOMStringBundleURL[] =
00146   "chrome://global/locale/dom/dom.properties";
00147 
00148 static PRThread *gDOMThread;
00149 
00150 static JSGCCallback gOldJSGCCallback;
00151 
00152 static PRBool sIsInitialized;
00153 static PRBool sDidShutdown;
00154 
00155 static PRInt32 sContextCount;
00156 
00157 static PRTime sMaxScriptRunTime;
00158 static PRTime sMaxChromeScriptRunTime;
00159 
00160 static nsIScriptSecurityManager *sSecurityManager;
00161 
00162 static nsICollation *gCollation;
00163 
00164 static nsIUnicodeDecoder *gDecoder;
00165 
00166 void JS_DLL_CALLBACK
00167 NS_ScriptErrorReporter(JSContext *cx,
00168                        const char *message,
00169                        JSErrorReport *report)
00170 {
00171   // XXX this means we are not going to get error reports on non DOM contexts
00172   nsIScriptContext *context = nsJSUtils::GetDynamicScriptContext(cx);
00173 
00174   nsEventStatus status = nsEventStatus_eIgnore;
00175 
00176   if (context) {
00177     nsIScriptGlobalObject *globalObject = context->GetGlobalObject();
00178 
00179     if (globalObject) {
00180       nsAutoString fileName, msg;
00181 
00182       if (report) {
00183         fileName.AssignWithConversion(report->filename);
00184 
00185         const PRUnichar *m = NS_REINTERPRET_CAST(const PRUnichar*,
00186                                                  report->ucmessage);
00187 
00188         if (m) {
00189           msg.Assign(m);
00190         }
00191       }
00192 
00193       if (msg.IsEmpty() && message) {
00194         msg.AssignWithConversion(message);
00195       }
00196 
00197       // First, notify the DOM that we have a script error.
00198       /* We do not try to report Out Of Memory via a dom
00199        * event because the dom event handler would encounter
00200        * an OOM exception trying to process the event, and
00201        * then we'd need to generate a new OOM event for that
00202        * new OOM instance -- this isn't pretty.
00203        */
00204       nsIDocShell *docShell = globalObject->GetDocShell();
00205       if (docShell &&
00206           (!report ||
00207            (report->errorNumber != JSMSG_OUT_OF_MEMORY &&
00208             !JSREPORT_IS_WARNING(report->flags)))) {
00209         static PRInt32 errorDepth; // Recursion prevention
00210         ++errorDepth;
00211 
00212         nsCOMPtr<nsPresContext> presContext;
00213         docShell->GetPresContext(getter_AddRefs(presContext));
00214 
00215         if (presContext && errorDepth < 2) {
00216           nsScriptErrorEvent errorevent(PR_TRUE, NS_SCRIPT_ERROR);
00217 
00218           errorevent.fileName = fileName.get();
00219           errorevent.errorMsg = msg.get();
00220           errorevent.lineNr = report ? report->lineno : 0;
00221 
00222           // HandleDOMEvent() must be synchronous for the recursion block
00223           // (errorDepth) to work.
00224           globalObject->HandleDOMEvent(presContext, &errorevent, nsnull,
00225                                        NS_EVENT_FLAG_INIT, &status);
00226         }
00227 
00228         --errorDepth;
00229       }
00230 
00231       if (status != nsEventStatus_eConsumeNoDefault) {
00232         // Make an nsIScriptError and populate it with information from
00233         // this error.
00234         nsCOMPtr<nsIScriptError> errorObject =
00235           do_CreateInstance("@mozilla.org/scripterror;1");
00236 
00237         if (errorObject != nsnull) {
00238           nsresult rv;
00239 
00240           const char *category = nsnull;
00241           // Set category to XUL or content, if possible.
00242           if (docShell) {
00243             nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(docShell, &rv));
00244             if (NS_SUCCEEDED(rv) && docShellTI) {
00245               PRInt32 docShellType;
00246               rv = docShellTI->GetItemType(&docShellType);
00247               if (NS_SUCCEEDED(rv)) {
00248                 category = docShellType == nsIDocShellTreeItem::typeChrome
00249                   ? "chrome javascript"
00250                   : "content javascript";
00251               }
00252             }
00253           }
00254 
00255           if (report) {
00256             PRUint32 column = report->uctokenptr - report->uclinebuf;
00257 
00258             rv = errorObject->Init(msg.get(), fileName.get(),
00259                                    NS_REINTERPRET_CAST(const PRUnichar*,
00260                                                        report->uclinebuf),
00261                                    report->lineno, column, report->flags,
00262                                    category);
00263           } else if (message) {
00264             rv = errorObject->Init(msg.get(), nsnull, nsnull, 0, 0, 0,
00265                                    category);
00266           }
00267 
00268           if (NS_SUCCEEDED(rv)) {
00269             nsCOMPtr<nsIConsoleService> consoleService =
00270               do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
00271             if (NS_SUCCEEDED(rv)) {
00272               consoleService->LogMessage(errorObject);
00273             }
00274           }
00275         }
00276       }
00277     }
00278   }
00279 
00280 #ifdef DEBUG
00281   // Print it to stderr as well, for the benefit of those invoking
00282   // mozilla with -console.
00283   nsCAutoString error;
00284   error.Assign("JavaScript ");
00285   if (!report) {
00286     error.Append("[no report]: ");
00287     error.Append(message);
00288   } else {
00289     if (JSREPORT_IS_STRICT(report->flags))
00290       error.Append("strict ");
00291     if (JSREPORT_IS_WARNING(report->flags))
00292       error.Append("warning: ");
00293     else
00294       error.Append("error: ");
00295     error.Append(report->filename);
00296     error.Append(", line ");
00297     error.AppendInt(report->lineno, 10);
00298     error.Append(": ");
00299     if (report->ucmessage) {
00300       AppendUTF16toUTF8(NS_REINTERPRET_CAST(const PRUnichar*, report->ucmessage),
00301                         error);
00302     } else {
00303       error.Append(message);
00304     }
00305     if (status != nsEventStatus_eIgnore && !JSREPORT_IS_WARNING(report->flags))
00306       error.Append(" Error was suppressed by event handler\n");
00307   }
00308   fprintf(stderr, "%s\n", error.get());
00309   fflush(stderr);
00310 #endif
00311 
00312 #ifdef PR_LOGGING
00313   if (report) {
00314     if (!gJSDiagnostics)
00315       gJSDiagnostics = PR_NewLogModule("JSDiagnostics");
00316 
00317     if (gJSDiagnostics) {
00318       PR_LOG(gJSDiagnostics,
00319              JSREPORT_IS_WARNING(report->flags) ? PR_LOG_WARNING : PR_LOG_ERROR,
00320              ("file %s, line %u: %s\n%s%s",
00321               report->filename, report->lineno, message,
00322               report->linebuf ? report->linebuf : "",
00323               (report->linebuf &&
00324                report->linebuf[strlen(report->linebuf)-1] != '\n')
00325               ? "\n"
00326               : ""));
00327     }
00328   }
00329 #endif
00330 
00331   // XXX do we really want to be doing this?
00332   ::JS_ClearPendingException(cx);
00333 }
00334 
00335 JS_STATIC_DLL_CALLBACK(JSBool)
00336 LocaleToUnicode(JSContext *cx, char *src, jsval *rval)
00337 {
00338   nsresult rv;
00339 
00340   if (!gDecoder) {
00341     // use app default locale
00342     nsCOMPtr<nsILocaleService> localeService = 
00343       do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
00344     if (NS_SUCCEEDED(rv)) {
00345       nsCOMPtr<nsILocale> appLocale;
00346       rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
00347       if (NS_SUCCEEDED(rv)) {
00348         nsAutoString localeStr;
00349         rv = appLocale->
00350           GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
00351         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get app locale info");
00352 
00353         nsCOMPtr<nsIPlatformCharset> platformCharset =
00354           do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
00355 
00356         if (NS_SUCCEEDED(rv)) {
00357           nsCAutoString charset;
00358           rv = platformCharset->GetDefaultCharsetForLocale(localeStr, charset);
00359           if (NS_SUCCEEDED(rv)) {
00360             // get/create unicode decoder for charset
00361             nsCOMPtr<nsICharsetConverterManager> ccm =
00362               do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
00363             if (NS_SUCCEEDED(rv))
00364               ccm->GetUnicodeDecoder(charset.get(), &gDecoder);
00365           }
00366         }
00367       }
00368     }
00369   }
00370 
00371   JSString *str = nsnull;
00372   PRInt32 srcLength = PL_strlen(src);
00373 
00374   if (gDecoder) {
00375     PRInt32 unicharLength = srcLength;
00376     PRUnichar *unichars = (PRUnichar *)malloc((srcLength + 1) * sizeof(PRUnichar));
00377     if (unichars) {
00378       rv = gDecoder->Convert(src, &srcLength, unichars, &unicharLength);
00379       if (NS_SUCCEEDED(rv)) {
00380         // terminate the returned string
00381         unichars[unicharLength] = 0;
00382 
00383         // nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
00384         if (unicharLength + 1 < srcLength + 1) {
00385           PRUnichar *shrunkUnichars =
00386             (PRUnichar *)realloc(unichars, (unicharLength + 1) * sizeof(PRUnichar));
00387           if (shrunkUnichars)
00388             unichars = shrunkUnichars;
00389         }
00390         str = JS_NewUCString(cx,
00391                              NS_REINTERPRET_CAST(jschar*, unichars),
00392                              unicharLength);
00393       }
00394       if (!str)
00395         free(unichars);
00396     }
00397   }
00398 
00399   if (!str) {
00400     nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
00401     return JS_FALSE;
00402   }
00403 
00404   *rval = STRING_TO_JSVAL(str);
00405   return JS_TRUE;
00406 }
00407 
00408 
00409 static JSBool
00410 ChangeCase(JSContext *cx, JSString *src, jsval *rval,
00411            void(* changeCaseFnc)(const nsAString&, nsAString&))
00412 {
00413   nsAutoString result;
00414   changeCaseFnc(nsDependentJSString(src), result);
00415 
00416   JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
00417   if (!ucstr) {
00418     return JS_FALSE;
00419   }
00420 
00421   *rval = STRING_TO_JSVAL(ucstr);
00422 
00423   return JS_TRUE;
00424 }
00425 
00426 static JSBool JS_DLL_CALLBACK
00427 LocaleToUpperCase(JSContext *cx, JSString *src, jsval *rval)
00428 {
00429   return ChangeCase(cx, src, rval, ToUpperCase);
00430 }
00431 
00432 static JSBool JS_DLL_CALLBACK
00433 LocaleToLowerCase(JSContext *cx, JSString *src, jsval *rval)
00434 {
00435   return ChangeCase(cx, src, rval, ToLowerCase);
00436 }
00437 
00438 static JSBool JS_DLL_CALLBACK
00439 LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
00440 {
00441   nsresult rv;
00442 
00443   if (!gCollation) {
00444     nsCOMPtr<nsILocaleService> localeService =
00445       do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
00446 
00447     if (NS_SUCCEEDED(rv)) {
00448       nsCOMPtr<nsILocale> locale;
00449       rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
00450 
00451       if (NS_SUCCEEDED(rv)) {
00452         nsCOMPtr<nsICollationFactory> colFactory =
00453           do_CreateInstance(kCollationFactoryCID, &rv);
00454 
00455         if (NS_SUCCEEDED(rv)) {
00456           rv = colFactory->CreateCollation(locale, &gCollation);
00457         }
00458       }
00459     }
00460 
00461     if (NS_FAILED(rv)) {
00462       nsDOMClassInfo::ThrowJSException(cx, rv);
00463 
00464       return JS_FALSE;
00465     }
00466   }
00467 
00468   PRInt32 result;
00469   rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
00470                                  nsDependentJSString(src1),
00471                                  nsDependentJSString(src2),
00472                                  &result);
00473 
00474   if (NS_FAILED(rv)) {
00475     nsDOMClassInfo::ThrowJSException(cx, rv);
00476 
00477     return JS_FALSE;
00478   }
00479 
00480   *rval = INT_TO_JSVAL(result);
00481 
00482   return JS_TRUE;
00483 }
00484 
00485 // The number of branch callbacks between calls to JS_MaybeGC
00486 #define MAYBE_GC_BRANCH_COUNT_MASK 0x00000fff // 4095
00487 
00488 // The number of branch callbacks before we even check if our start
00489 // timestamp is initialized. This is a fairly low number as we want to
00490 // initialize the timestamp early enough to not waste much time before
00491 // we get there, but we don't want to bother doing this too early as
00492 // it's not generally necessary.
00493 #define INITIALIZE_TIME_BRANCH_COUNT_MASK 0x000000ff // 255
00494 
00495 // This function is called after each JS branch execution
00496 JSBool JS_DLL_CALLBACK
00497 nsJSContext::DOMBranchCallback(JSContext *cx, JSScript *script)
00498 {
00499   // Get the native context
00500   nsJSContext *ctx = NS_STATIC_CAST(nsJSContext *, ::JS_GetContextPrivate(cx));
00501 
00502   PRUint32 callbackCount = ++ctx->mBranchCallbackCount;
00503 
00504   if (callbackCount & INITIALIZE_TIME_BRANCH_COUNT_MASK) {
00505     return JS_TRUE;
00506   }
00507 
00508   if (callbackCount == INITIALIZE_TIME_BRANCH_COUNT_MASK + 1 &&
00509       LL_IS_ZERO(ctx->mBranchCallbackTime)) {
00510     // Initialize mBranchCallbackTime to start timing how long the
00511     // script has run
00512     ctx->mBranchCallbackTime = PR_Now();
00513 
00514     ctx->mIsTrackingChromeCodeTime =
00515       ::JS_IsSystemObject(cx, ::JS_GetGlobalObject(cx));
00516 
00517     return JS_TRUE;
00518   }
00519 
00520   if (callbackCount & MAYBE_GC_BRANCH_COUNT_MASK) {
00521     return JS_TRUE;
00522   }
00523 
00524   // XXX Save the branch callback time so we can restore it after the GC,
00525   // because GCing can cause JS to run on our context, causing our
00526   // ScriptEvaluated to be called, and clearing our branch callback time and
00527   // count. See bug 302333.
00528   PRTime callbackTime = ctx->mBranchCallbackTime;
00529 
00530   // Run the GC if we get this far.
00531   JS_MaybeGC(cx);
00532 
00533   // Now restore the callback time and count, in case they got reset.
00534   ctx->mBranchCallbackTime = callbackTime;
00535   ctx->mBranchCallbackCount = callbackCount;
00536 
00537   PRTime now = PR_Now();
00538 
00539   PRTime duration;
00540   LL_SUB(duration, now, callbackTime);
00541 
00542   // Check the amount of time this script has been running
00543   if (duration < (ctx->mIsTrackingChromeCodeTime ?
00544                   sMaxChromeScriptRunTime : sMaxScriptRunTime)) {
00545     return JS_TRUE;
00546   }
00547 
00548   // If we get here we're most likely executing an infinite loop in JS,
00549   // we'll tell the user about this and we'll give the user the option
00550   // of stopping the execution of the script.
00551   nsIScriptGlobalObject *global = ctx->GetGlobalObject();
00552   NS_ENSURE_TRUE(global, JS_TRUE);
00553 
00554   nsIDocShell *docShell = global->GetDocShell();
00555   NS_ENSURE_TRUE(docShell, JS_TRUE);
00556 
00557   nsCOMPtr<nsIInterfaceRequestor> ireq(do_QueryInterface(docShell));
00558   NS_ENSURE_TRUE(ireq, JS_TRUE);
00559 
00560   // Get the nsIPrompt interface from the docshell
00561   nsCOMPtr<nsIPrompt> prompt;
00562   ireq->GetInterface(NS_GET_IID(nsIPrompt), getter_AddRefs(prompt));
00563   NS_ENSURE_TRUE(prompt, JS_TRUE);
00564 
00565   nsresult rv;
00566 
00567   // Check if we should offer the option to debug
00568   PRBool debugPossible = (cx->runtime && cx->runtime->debuggerHandler);
00569 #ifdef MOZ_JSDEBUGGER
00570   // Get the debugger service if necessary.
00571   if (debugPossible) {
00572     PRBool jsds_IsOn = PR_FALSE;
00573     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
00574     nsCOMPtr<jsdIExecutionHook> jsdHook;  
00575     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
00576   
00577     // Check if there's a user for the debugger service that's 'on' for us
00578     if (NS_SUCCEEDED(rv)) {
00579       jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
00580       jsds->GetIsOn(&jsds_IsOn);
00581       if (jsds_IsOn) { // If this is not true, the next call would start jsd...
00582         rv = jsds->OnForRuntime(cx->runtime);
00583         jsds_IsOn = NS_SUCCEEDED(rv);
00584       }
00585     }
00586 
00587     // If there is a debug handler registered for this runtime AND
00588     // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
00589     // then something useful will be done with our request to debug.
00590     debugPossible = ((jsds_IsOn && (jsdHook != nsnull)) || !jsds_IsOn);
00591   }
00592 #endif
00593 
00594   // Get localizable strings
00595   nsCOMPtr<nsIStringBundleService>
00596     stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
00597   if (!stringService)
00598     return JS_TRUE;
00599 
00600   nsCOMPtr<nsIStringBundle> bundle;
00601   stringService->CreateBundle(kDOMStringBundleURL, getter_AddRefs(bundle));
00602   if (!bundle)
00603     return JS_TRUE;
00604 
00605   nsXPIDLString title, msg, stopButton, waitButton, debugButton;
00606 
00607   rv = bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptTitle").get(),
00608                                   getter_Copies(title));
00609   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("StopScriptButton").get(),
00610                                   getter_Copies(stopButton));
00611   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("WaitForScriptButton").get(),
00612                                   getter_Copies(waitButton));
00613 
00614   if (debugPossible) {
00615     rv |= bundle->GetStringFromName(NS_LITERAL_STRING("DebugScriptButton").get(),
00616                                     getter_Copies(debugButton));
00617     rv |= bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptWithDebugMessage").get(),
00618                                    getter_Copies(msg));
00619   }
00620   else {
00621     rv |= bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptMessage").get(),
00622                                    getter_Copies(msg));
00623   }
00624 
00625   //GetStringFromName can return NS_OK and still give NULL string
00626   if (NS_FAILED(rv) || !title || !msg || !stopButton || !waitButton ||
00627       (debugPossible && !debugButton)) {
00628     NS_ERROR("Failed to get localized strings.");
00629     return JS_TRUE;
00630   }
00631 
00632   PRInt32 buttonPressed = 1; //In case user exits dialog by clicking X
00633   PRUint32 buttonFlags = (nsIPrompt::BUTTON_TITLE_IS_STRING *
00634                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
00635 
00636   // Add a third button if necessary:
00637   if (debugPossible)
00638     buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
00639 
00640   // Open the dialog.
00641   rv = prompt->ConfirmEx(title, msg, buttonFlags, stopButton, waitButton,
00642                          debugButton, nsnull, nsnull, &buttonPressed);
00643 
00644   if (NS_FAILED(rv) || (buttonPressed == 1)) {
00645     // Allow the script to run this long again
00646     ctx->mBranchCallbackTime = PR_Now();
00647     return JS_TRUE;
00648   }
00649   else if ((buttonPressed == 2) && debugPossible) {
00650     // Debug the script
00651     jsval rval;
00652     switch(cx->runtime->debuggerHandler(cx, script, cx->fp->pc, &rval, 
00653                                         cx->runtime->debuggerHandlerData)) {
00654       case JSTRAP_RETURN:
00655         cx->fp->rval = rval;
00656         return JS_TRUE;
00657       case JSTRAP_ERROR:
00658         cx->throwing = JS_FALSE;
00659         return JS_FALSE;
00660       case JSTRAP_THROW:
00661         JS_SetPendingException(cx, rval);
00662         return JS_FALSE;
00663       case JSTRAP_CONTINUE:
00664       default:
00665         return JS_TRUE;
00666     }
00667   }
00668 
00669   return JS_FALSE;
00670 }
00671 
00672 #define JS_OPTIONS_DOT_STR "javascript.options."
00673 
00674 static const char js_options_dot_str[]   = JS_OPTIONS_DOT_STR;
00675 static const char js_strict_option_str[] = JS_OPTIONS_DOT_STR "strict";
00676 static const char js_werror_option_str[] = JS_OPTIONS_DOT_STR "werror";
00677 #ifdef JS_GC_ZEAL
00678 static const char js_zeal_option_str[]   = JS_OPTIONS_DOT_STR "gczeal";
00679 #endif
00680 
00681 
00682 int PR_CALLBACK
00683 nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
00684 {
00685   nsJSContext *context = NS_REINTERPRET_CAST(nsJSContext *, data);
00686   PRUint32 oldDefaultJSOptions = context->mDefaultJSOptions;
00687   PRUint32 newDefaultJSOptions = oldDefaultJSOptions;
00688 
00689   PRBool strict = nsContentUtils::GetBoolPref(js_strict_option_str);
00690   if (strict)
00691     newDefaultJSOptions |= JSOPTION_STRICT;
00692   else
00693     newDefaultJSOptions &= ~JSOPTION_STRICT;
00694 
00695   PRBool werror = nsContentUtils::GetBoolPref(js_werror_option_str);
00696   if (werror)
00697     newDefaultJSOptions |= JSOPTION_WERROR;
00698   else
00699     newDefaultJSOptions &= ~JSOPTION_WERROR;
00700 
00701   if (newDefaultJSOptions != oldDefaultJSOptions) {
00702     // Set options only if we used the old defaults; otherwise the page has
00703     // customized some via the options object and we defer to its wisdom.
00704     if (::JS_GetOptions(context->mContext) == oldDefaultJSOptions)
00705       ::JS_SetOptions(context->mContext, newDefaultJSOptions);
00706 
00707     // Save the new defaults for the next page load (InitContext).
00708     context->mDefaultJSOptions = newDefaultJSOptions;
00709   }
00710 
00711 #ifdef JS_GC_ZEAL
00712   PRInt32 zeal = nsContentUtils::GetIntPref(js_zeal_option_str, -1);
00713   if (zeal >= 0)
00714     ::JS_SetGCZeal(context->mContext, (PRUint8)zeal);
00715 #endif
00716 
00717   return 0;
00718 }
00719 
00720 nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
00721 {
00722 
00723   ++sContextCount;
00724 
00725   mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS
00726                     | JSOPTION_NATIVE_BRANCH_CALLBACK
00727 #ifdef DEBUG
00728                     | JSOPTION_STRICT   // lint catching for development
00729 #endif
00730     ;
00731 
00732   // Let xpconnect resync its JSContext tracker. We do this before creating
00733   // a new JSContext just in case the heap manager recycles the JSContext
00734   // struct.
00735   nsContentUtils::XPConnect()->SyncJSContexts();
00736 
00737   mContext = ::JS_NewContext(aRuntime, gStackSize);
00738   if (mContext) {
00739     ::JS_SetContextPrivate(mContext, NS_STATIC_CAST(nsIScriptContext *, this));
00740 
00741     // Make sure the new context gets the default context options
00742     ::JS_SetOptions(mContext, mDefaultJSOptions);
00743 
00744     // Check for the JS strict option, which enables extra error checks
00745     nsContentUtils::RegisterPrefCallback(js_options_dot_str,
00746                                          JSOptionChangedCallback,
00747                                          this);
00748     JSOptionChangedCallback(js_options_dot_str, this);
00749 
00750     ::JS_SetBranchCallback(mContext, DOMBranchCallback);
00751 
00752     static JSLocaleCallbacks localeCallbacks =
00753       {
00754         LocaleToUpperCase,
00755         LocaleToLowerCase,
00756         LocaleCompare,
00757         LocaleToUnicode
00758       };
00759 
00760     ::JS_SetLocaleCallbacks(mContext, &localeCallbacks);
00761   }
00762   mIsInitialized = PR_FALSE;
00763   mNumEvaluations = 0;
00764   mOwner = nsnull;
00765   mTerminations = nsnull;
00766   mScriptsEnabled = PR_TRUE;
00767   mBranchCallbackCount = 0;
00768   mBranchCallbackTime = LL_ZERO;
00769   mProcessingScriptTag = PR_FALSE;
00770   mIsTrackingChromeCodeTime = PR_FALSE;
00771 
00772   InvalidateContextAndWrapperCache();
00773 }
00774 
00775 nsJSContext::~nsJSContext()
00776 {
00777   NS_PRECONDITION(!mTerminations, "Shouldn't have termination funcs by now");
00778                   
00779   // Cope with JS_NewContext failure in ctor (XXXbe move NewContext to Init?)
00780   if (!mContext)
00781     return;
00782 
00783   // Clear our entry in the JSContext, bugzilla bug 66413
00784   ::JS_SetContextPrivate(mContext, nsnull);
00785 
00786   // Clear the branch callback, bugzilla bug 238218
00787   ::JS_SetBranchCallback(mContext, nsnull);
00788 
00789   // Unregister our "javascript.options.*" pref-changed callback.
00790   nsContentUtils::UnregisterPrefCallback(js_options_dot_str,
00791                                          JSOptionChangedCallback,
00792                                          this);
00793 
00794   // Release mGlobalWrapperRef before the context is destroyed
00795   mGlobalWrapperRef = nsnull;
00796 
00797   // Let xpconnect destroy the JSContext when it thinks the time is right.
00798   nsIXPConnect *xpc = nsContentUtils::XPConnect();
00799   if (xpc) {
00800     PRBool do_gc = mGCOnDestruction && !sGCTimer && sReadyForGC;
00801 
00802     xpc->ReleaseJSContext(mContext, !do_gc);
00803   } else {
00804     ::JS_DestroyContext(mContext);
00805   }
00806 
00807   --sContextCount;
00808 
00809   if (!sContextCount && sDidShutdown) {
00810     // The last context is being deleted, and we're already in the
00811     // process of shutting down, release the JS runtime service, and
00812     // the security manager.
00813 
00814     NS_IF_RELEASE(sRuntimeService);
00815     NS_IF_RELEASE(sSecurityManager);
00816     NS_IF_RELEASE(gCollation);
00817     NS_IF_RELEASE(gDecoder);
00818   }
00819 }
00820 
00821 // QueryInterface implementation for nsJSContext
00822 NS_INTERFACE_MAP_BEGIN(nsJSContext)
00823   NS_INTERFACE_MAP_ENTRY(nsIScriptContext)
00824   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify)
00825   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
00826   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptContext)
00827 NS_INTERFACE_MAP_END
00828 
00829 
00830 NS_IMPL_ADDREF(nsJSContext)
00831 NS_IMPL_RELEASE(nsJSContext)
00832 
00833 
00834 nsresult
00835 nsJSContext::EvaluateStringWithValue(const nsAString& aScript,
00836                                      void *aScopeObject,
00837                                      nsIPrincipal *aPrincipal,
00838                                      const char *aURL,
00839                                      PRUint32 aLineNo,
00840                                      const char* aVersion,
00841                                      void* aRetValue,
00842                                      PRBool* aIsUndefined)
00843 {
00844   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
00845 
00846   if (!mScriptsEnabled) {
00847     if (aIsUndefined) {
00848       *aIsUndefined = PR_TRUE;
00849     }
00850 
00851     return NS_OK;
00852   }
00853 
00854   nsresult rv;
00855   if (!aScopeObject)
00856     aScopeObject = ::JS_GetGlobalObject(mContext);
00857 
00858   // Safety first: get an object representing the script's principals, i.e.,
00859   // the entities who signed this script, or the fully-qualified-domain-name
00860   // or "codebase" from which it was loaded.
00861   JSPrincipals *jsprin;
00862   nsIPrincipal *principal = aPrincipal;
00863   if (aPrincipal) {
00864     aPrincipal->GetJSPrincipals(mContext, &jsprin);
00865   }
00866   else {
00867     nsIScriptGlobalObject *global = GetGlobalObject();
00868     if (!global)
00869       return NS_ERROR_FAILURE;
00870     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
00871       do_QueryInterface(global, &rv);
00872     if (NS_FAILED(rv))
00873       return NS_ERROR_FAILURE;
00874     principal = objPrincipal->GetPrincipal();
00875     if (!principal)
00876       return NS_ERROR_FAILURE;
00877     principal->GetJSPrincipals(mContext, &jsprin);
00878   }
00879   // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
00880 
00881   PRBool ok = PR_FALSE;
00882 
00883   rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
00884   if (NS_FAILED(rv)) {
00885     JSPRINCIPALS_DROP(mContext, jsprin);
00886     return NS_ERROR_FAILURE;
00887   }
00888 
00889   // Push our JSContext on the current thread's context stack so JS called
00890   // from native code via XPConnect uses the right context.  Do this whether
00891   // or not the SecurityManager said "ok", in order to simplify control flow
00892   // below where we pop before returning.
00893   nsCOMPtr<nsIJSContextStack> stack =
00894            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
00895   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
00896     JSPRINCIPALS_DROP(mContext, jsprin);
00897     return NS_ERROR_FAILURE;
00898   }
00899 
00900   jsval val;
00901 
00902   nsJSContext::TerminationFuncHolder holder(this);
00903   if (ok) {
00904     JSVersion newVersion = JSVERSION_UNKNOWN;
00905 
00906     // SecurityManager said "ok", but don't execute if aVersion is specified
00907     // and unknown.  Do execute with the default version (and avoid thrashing
00908     // the context's version) if aVersion is not specified.
00909     ok = (!aVersion ||
00910           (newVersion = ::JS_StringToVersion(aVersion)) != JSVERSION_UNKNOWN);
00911     if (ok) {
00912       JSVersion oldVersion = JSVERSION_UNKNOWN;
00913 
00914       if (aVersion)
00915         oldVersion = ::JS_SetVersion(mContext, newVersion);
00916       ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
00917                                               (JSObject *)aScopeObject,
00918                                               jsprin,
00919                                               (jschar*)PromiseFlatString(aScript).get(),
00920                                               aScript.Length(),
00921                                               aURL,
00922                                               aLineNo,
00923                                               &val);
00924 
00925       if (aVersion) {
00926         ::JS_SetVersion(mContext, oldVersion);
00927       }
00928 
00929       if (!ok) {
00930         // Tell XPConnect about any pending exceptions. This is needed
00931         // to avoid dropping JS exceptions in case we got here through
00932         // nested calls through XPConnect.
00933 
00934         nsContentUtils::NotifyXPCIfExceptionPending(mContext);
00935       }
00936     }
00937   }
00938 
00939   // Whew!  Finally done with these manually ref-counted things.
00940   JSPRINCIPALS_DROP(mContext, jsprin);
00941 
00942   // If all went well, convert val to a string (XXXbe unless undefined?).
00943   if (ok) {
00944     if (aIsUndefined) {
00945       *aIsUndefined = JSVAL_IS_VOID(val);
00946     }
00947 
00948     *NS_STATIC_CAST(jsval*, aRetValue) = val;
00949   }
00950   else {
00951     if (aIsUndefined) {
00952       *aIsUndefined = PR_TRUE;
00953     }
00954   }
00955 
00956   // Pop here, after JS_ValueToString and any other possible evaluation.
00957   if (NS_FAILED(stack->Pop(nsnull)))
00958     rv = NS_ERROR_FAILURE;
00959 
00960   // ScriptEvaluated needs to come after we pop the stack
00961   ScriptEvaluated(PR_TRUE);
00962 
00963   return rv;
00964 
00965 }
00966 
00967 // Helper function to convert a jsval to an nsAString, and set
00968 // exception flags if the conversion fails.
00969 static nsresult
00970 JSValueToAString(JSContext *cx, jsval val, nsAString *result,
00971                  PRBool *isUndefined)
00972 {
00973   if (isUndefined) {
00974     *isUndefined = JSVAL_IS_VOID(val);
00975   }
00976 
00977   if (!result) {
00978     return NS_OK;
00979   }
00980 
00981   JSString* jsstring = ::JS_ValueToString(cx, val);
00982   if (jsstring) {
00983     result->Assign(NS_REINTERPRET_CAST(const PRUnichar*,
00984                                        ::JS_GetStringChars(jsstring)),
00985                    ::JS_GetStringLength(jsstring));
00986   } else {
00987     result->Truncate();
00988 
00989     // We failed to convert val to a string. We're either OOM, or the
00990     // security manager denied access to .toString(), or somesuch, on
00991     // an object. Treat this case as if the result were undefined.
00992 
00993     if (isUndefined) {
00994       *isUndefined = PR_TRUE;
00995     }
00996 
00997     if (!::JS_IsExceptionPending(cx)) {
00998       // JS_ValueToString() returned null w/o an exception
00999       // pending. That means we're OOM.
01000 
01001       return NS_ERROR_OUT_OF_MEMORY;
01002     }
01003 
01004     // Tell XPConnect about any pending exceptions. This is needed to
01005     // avoid dropping JS exceptions in case we got here through nested
01006     // calls through XPConnect.
01007 
01008     nsContentUtils::NotifyXPCIfExceptionPending(cx);
01009   }
01010 
01011   return NS_OK;
01012 }
01013 
01014 nsresult
01015 nsJSContext::EvaluateString(const nsAString& aScript,
01016                             void *aScopeObject,
01017                             nsIPrincipal *aPrincipal,
01018                             const char *aURL,
01019                             PRUint32 aLineNo,
01020                             const char* aVersion,
01021                             nsAString *aRetValue,
01022                             PRBool* aIsUndefined)
01023 {
01024   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01025 
01026   if (!mScriptsEnabled) {
01027     *aIsUndefined = PR_TRUE;
01028 
01029     if (aRetValue) {
01030       aRetValue->Truncate();
01031     }
01032 
01033     return NS_OK;
01034   }
01035 
01036   nsresult rv;
01037   if (!aScopeObject)
01038     aScopeObject = ::JS_GetGlobalObject(mContext);
01039 
01040   // Safety first: get an object representing the script's principals, i.e.,
01041   // the entities who signed this script, or the fully-qualified-domain-name
01042   // or "codebase" from which it was loaded.
01043   JSPrincipals *jsprin;
01044   nsIPrincipal *principal = aPrincipal;
01045   if (aPrincipal) {
01046     aPrincipal->GetJSPrincipals(mContext, &jsprin);
01047   }
01048   else {
01049     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
01050       do_QueryInterface(GetGlobalObject(), &rv);
01051     if (NS_FAILED(rv))
01052       return NS_ERROR_FAILURE;
01053     principal = objPrincipal->GetPrincipal();
01054     if (!principal)
01055       return NS_ERROR_FAILURE;
01056     principal->GetJSPrincipals(mContext, &jsprin);
01057   }
01058 
01059   // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
01060 
01061   PRBool ok = PR_FALSE;
01062 
01063   rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
01064   if (NS_FAILED(rv)) {
01065     JSPRINCIPALS_DROP(mContext, jsprin);
01066     return NS_ERROR_FAILURE;
01067   }
01068 
01069   // Push our JSContext on the current thread's context stack so JS called
01070   // from native code via XPConnect uses the right context.  Do this whether
01071   // or not the SecurityManager said "ok", in order to simplify control flow
01072   // below where we pop before returning.
01073   nsCOMPtr<nsIJSContextStack> stack =
01074            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01075   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
01076     JSPRINCIPALS_DROP(mContext, jsprin);
01077     return NS_ERROR_FAILURE;
01078   }
01079 
01080   // The result of evaluation, used only if there were no errors.  This need
01081   // not be a GC root currently, provided we run the GC only from the branch
01082   // callback or from ScriptEvaluated.  TODO: use JS_Begin/EndRequest to keep
01083   // the GC from racing with JS execution on any thread.
01084   jsval val;
01085 
01086   nsJSContext::TerminationFuncHolder holder(this);
01087   if (ok) {
01088     JSVersion newVersion = JSVERSION_UNKNOWN;
01089 
01090     // SecurityManager said "ok", but don't execute if aVersion is specified
01091     // and unknown.  Do execute with the default version (and avoid thrashing
01092     // the context's version) if aVersion is not specified.
01093     ok = (!aVersion ||
01094           (newVersion = ::JS_StringToVersion(aVersion)) != JSVERSION_UNKNOWN);
01095     if (ok) {
01096       JSVersion oldVersion = JSVERSION_UNKNOWN;
01097 
01098       if (aVersion)
01099         oldVersion = ::JS_SetVersion(mContext, newVersion);
01100       ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
01101                                               (JSObject *)aScopeObject,
01102                                               jsprin,
01103                                               (jschar*)PromiseFlatString(aScript).get(),
01104                                               aScript.Length(),
01105                                               aURL,
01106                                               aLineNo,
01107                                               &val);
01108 
01109       if (aVersion) {
01110         ::JS_SetVersion(mContext, oldVersion);
01111       }
01112 
01113       if (!ok) {
01114         // Tell XPConnect about any pending exceptions. This is needed
01115         // to avoid dropping JS exceptions in case we got here through
01116         // nested calls through XPConnect.
01117 
01118         nsContentUtils::NotifyXPCIfExceptionPending(mContext);
01119       }
01120     }
01121   }
01122 
01123   // Whew!  Finally done with these manually ref-counted things.
01124   JSPRINCIPALS_DROP(mContext, jsprin);
01125 
01126   // If all went well, convert val to a string (XXXbe unless undefined?).
01127   if (ok) {
01128     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
01129   }
01130   else {
01131     if (aIsUndefined) {
01132       *aIsUndefined = PR_TRUE;
01133     }
01134 
01135     if (aRetValue) {
01136       aRetValue->Truncate();
01137     }
01138   }
01139 
01140   // Pop here, after JS_ValueToString and any other possible evaluation.
01141   if (NS_FAILED(stack->Pop(nsnull)))
01142     rv = NS_ERROR_FAILURE;
01143 
01144   // ScriptEvaluated needs to come after we pop the stack
01145   ScriptEvaluated(PR_TRUE);
01146 
01147   return rv;
01148 }
01149 
01150 nsresult
01151 nsJSContext::CompileScript(const PRUnichar* aText,
01152                            PRInt32 aTextLength,
01153                            void *aScopeObject,
01154                            nsIPrincipal *aPrincipal,
01155                            const char *aURL,
01156                            PRUint32 aLineNo,
01157                            const char* aVersion,
01158                            void** aScriptObject)
01159 {
01160   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01161 
01162   nsresult rv;
01163   NS_ENSURE_ARG_POINTER(aPrincipal);
01164 
01165   if (!aScopeObject)
01166     aScopeObject = ::JS_GetGlobalObject(mContext);
01167 
01168   JSPrincipals *jsprin;
01169   aPrincipal->GetJSPrincipals(mContext, &jsprin);
01170   // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
01171 
01172   PRBool ok = PR_FALSE;
01173 
01174   rv = sSecurityManager->CanExecuteScripts(mContext, aPrincipal, &ok);
01175   if (NS_FAILED(rv)) {
01176     JSPRINCIPALS_DROP(mContext, jsprin);
01177     return NS_ERROR_FAILURE;
01178   }
01179 
01180   *aScriptObject = nsnull;
01181   if (ok) {
01182     JSVersion newVersion = JSVERSION_UNKNOWN;
01183 
01184     // SecurityManager said "ok", but don't compile if aVersion is specified
01185     // and unknown.  Do compile with the default version (and avoid thrashing
01186     // the context's version) if aVersion is not specified.
01187     if (!aVersion ||
01188         (newVersion = ::JS_StringToVersion(aVersion)) != JSVERSION_UNKNOWN) {
01189       JSVersion oldVersion = JSVERSION_UNKNOWN;
01190       if (aVersion)
01191         oldVersion = ::JS_SetVersion(mContext, newVersion);
01192 
01193       JSScript* script =
01194         ::JS_CompileUCScriptForPrincipals(mContext,
01195                                           (JSObject*) aScopeObject,
01196                                           jsprin,
01197                                           (jschar*) aText,
01198                                           aTextLength,
01199                                           aURL,
01200                                           aLineNo);
01201       if (script) {
01202         *aScriptObject = (void*) ::JS_NewScriptObject(mContext, script);
01203         if (! *aScriptObject) {
01204           ::JS_DestroyScript(mContext, script);
01205           script = nsnull;
01206         }
01207       }
01208       if (!script)
01209         rv = NS_ERROR_OUT_OF_MEMORY;
01210 
01211       if (aVersion)
01212         ::JS_SetVersion(mContext, oldVersion);
01213     }
01214   }
01215 
01216   // Whew!  Finally done with these manually ref-counted things.
01217   JSPRINCIPALS_DROP(mContext, jsprin);
01218   return rv;
01219 }
01220 
01221 nsresult
01222 nsJSContext::ExecuteScript(void* aScriptObject,
01223                            void *aScopeObject,
01224                            nsAString* aRetValue,
01225                            PRBool* aIsUndefined)
01226 {
01227   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01228 
01229   if (!mScriptsEnabled) {
01230     if (aIsUndefined) {
01231       *aIsUndefined = PR_TRUE;
01232     }
01233 
01234     if (aRetValue) {
01235       aRetValue->Truncate();
01236     }
01237 
01238     return NS_OK;
01239   }
01240 
01241   nsresult rv;
01242 
01243   if (!aScopeObject)
01244     aScopeObject = ::JS_GetGlobalObject(mContext);
01245 
01246   // Push our JSContext on our thread's context stack, in case native code
01247   // called from JS calls back into JS via XPConnect.
01248   nsCOMPtr<nsIJSContextStack> stack =
01249            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01250   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
01251     return NS_ERROR_FAILURE;
01252   }
01253 
01254   // The result of evaluation, used only if there were no errors.  This need
01255   // not be a GC root currently, provided we run the GC only from the branch
01256   // callback or from ScriptEvaluated.  TODO: use JS_Begin/EndRequest to keep
01257   // the GC from racing with JS execution on any thread.
01258   jsval val;
01259   JSBool ok;
01260 
01261   nsJSContext::TerminationFuncHolder holder(this);
01262   ok = ::JS_ExecuteScript(mContext,
01263                           (JSObject*) aScopeObject,
01264                           (JSScript*) ::JS_GetPrivate(mContext,
01265                                                     (JSObject*)aScriptObject),
01266                           &val);
01267 
01268   if (ok) {
01269     // If all went well, convert val to a string (XXXbe unless undefined?).
01270 
01271     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
01272   } else {
01273     if (aIsUndefined) {
01274       *aIsUndefined = PR_TRUE;
01275     }
01276 
01277     if (aRetValue) {
01278       aRetValue->Truncate();
01279     }
01280 
01281     // Tell XPConnect about any pending exceptions. This is needed to
01282     // avoid dropping JS exceptions in case we got here through nested
01283     // calls through XPConnect.
01284 
01285     nsContentUtils::NotifyXPCIfExceptionPending(mContext);
01286   }
01287 
01288   // Pop here, after JS_ValueToString and any other possible evaluation.
01289   if (NS_FAILED(stack->Pop(nsnull)))
01290     rv = NS_ERROR_FAILURE;
01291 
01292   // ScriptEvaluated needs to come after we pop the stack
01293   ScriptEvaluated(PR_TRUE);
01294 
01295   return rv;
01296 }
01297 
01298 
01299 static inline const char *
01300 AtomToEventHandlerName(nsIAtom *aName)
01301 {
01302   const char *name;
01303 
01304   aName->GetUTF8String(&name);
01305 
01306 #ifdef DEBUG
01307   const char *cp;
01308   char c;
01309   for (cp = name; *cp != '\0'; ++cp)
01310   {
01311     c = *cp;
01312     NS_ASSERTION (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'),
01313                   "non-ASCII non-alphabetic event handler name");
01314   }
01315 #endif
01316 
01317   return name;
01318 }
01319 
01320 nsresult
01321 nsJSContext::CompileEventHandler(void *aTarget, nsIAtom *aName,
01322                                  const char *aEventName,
01323                                  const nsAString& aBody,
01324                                  const char *aURL, PRUint32 aLineNo,
01325                                  PRBool aShared, void** aHandler)
01326 {
01327   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01328 
01329   if (!sSecurityManager) {
01330     NS_ERROR("Huh, we need a script security manager to compile "
01331              "an event handler!");
01332 
01333     return NS_ERROR_UNEXPECTED;
01334   }
01335 
01336   JSObject *target = (JSObject*)aTarget;
01337 
01338   JSPrincipals *jsprin = nsnull;
01339 
01340   if (target) {
01341     // Get the principal of the event target (the object principal),
01342     // don't get the principal of the global object in this context
01343     // since that opens up security exploits with delayed event
01344     // handler compilation on stale DOM objects (objects that live in
01345     // a document that has already been unloaded).
01346     nsCOMPtr<nsIPrincipal> prin;
01347     nsresult rv = sSecurityManager->GetObjectPrincipal(mContext, target,
01348                                                        getter_AddRefs(prin));
01349     NS_ENSURE_SUCCESS(rv, rv);
01350 
01351     prin->GetJSPrincipals(mContext, &jsprin);
01352     NS_ENSURE_TRUE(jsprin, NS_ERROR_NOT_AVAILABLE);
01353   }
01354 
01355   const char *charName = AtomToEventHandlerName(aName);
01356 
01357   const char *argList[] = { aEventName };
01358 
01359   JSFunction* fun =
01360       ::JS_CompileUCFunctionForPrincipals(mContext,
01361                                           aShared ? nsnull : target, jsprin,
01362                                           charName, 1, argList,
01363                                           (jschar*)PromiseFlatString(aBody).get(),
01364                                           aBody.Length(),
01365                                           aURL, aLineNo);
01366 
01367   if (jsprin) {
01368     JSPRINCIPALS_DROP(mContext, jsprin);
01369   }
01370   if (!fun) {
01371     return NS_ERROR_FAILURE;
01372   }
01373 
01374   JSObject *handler = ::JS_GetFunctionObject(fun);
01375   if (aHandler)
01376     *aHandler = (void*) handler;
01377   return NS_OK;
01378 }
01379 
01380 nsresult
01381 nsJSContext::CompileFunction(void* aTarget,
01382                              const nsACString& aName,
01383                              PRUint32 aArgCount,
01384                              const char** aArgArray,
01385                              const nsAString& aBody,
01386                              const char* aURL,
01387                              PRUint32 aLineNo,
01388                              PRBool aShared,
01389                              void** aFunctionObject)
01390 {
01391   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01392 
01393   JSPrincipals *jsprin = nsnull;
01394 
01395   nsIScriptGlobalObject *global = GetGlobalObject();
01396   if (global) {
01397     // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
01398     nsCOMPtr<nsIScriptObjectPrincipal> globalData = do_QueryInterface(global);
01399     if (globalData) {
01400       nsIPrincipal *prin = globalData->GetPrincipal();
01401       if (!prin)
01402         return NS_ERROR_FAILURE;
01403       prin->GetJSPrincipals(mContext, &jsprin);
01404     }
01405   }
01406 
01407   JSObject *target = (JSObject*)aTarget;
01408   JSFunction* fun =
01409       ::JS_CompileUCFunctionForPrincipals(mContext,
01410                                           aShared ? nsnull : target, jsprin,
01411                                           PromiseFlatCString(aName).get(),
01412                                           aArgCount, aArgArray,
01413                                           (jschar*)PromiseFlatString(aBody).get(),
01414                                           aBody.Length(),
01415                                           aURL, aLineNo);
01416 
01417   if (jsprin)
01418     JSPRINCIPALS_DROP(mContext, jsprin);
01419   if (!fun)
01420     return NS_ERROR_FAILURE;
01421 
01422   JSObject *handler = ::JS_GetFunctionObject(fun);
01423   if (aFunctionObject)
01424     *aFunctionObject = (void*) handler;
01425   return NS_OK;
01426 }
01427 
01428 nsresult
01429 nsJSContext::CallEventHandler(JSObject *aTarget, JSObject *aHandler,
01430                               uintN argc, jsval *argv, jsval *rval)
01431 {
01432   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01433 
01434   *rval = JSVAL_VOID;
01435 
01436   if (!mScriptsEnabled) {
01437     return NS_OK;
01438   }
01439 
01440   // This one's a lot easier than EvaluateString because we don't have to
01441   // hassle with principals: they're already compiled into the JS function.
01442   nsresult rv;
01443 
01444   nsCOMPtr<nsIJSContextStack> stack =
01445     do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01446   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext)))
01447     return NS_ERROR_FAILURE;
01448 
01449   // check if the event handler can be run on the object in question
01450   rv = sSecurityManager->CheckFunctionAccess(mContext, aHandler, aTarget);
01451   if (NS_SUCCEEDED(rv)) {
01452     // We're not done yet!  Some event listeners are confused about their
01453     // script context, so check whether we might actually be the wrong script
01454     // context.  To be safe, do CheckFunctionAccess checks for both.
01455     nsCOMPtr<nsIContent> content;
01456     const JSClass *jsClass = JS_GET_CLASS(mContext, aTarget);
01457     if (jsClass &&
01458         !((~jsClass->flags) & (JSCLASS_HAS_PRIVATE |
01459                                JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
01460       nsISupports *priv =
01461         NS_STATIC_CAST(nsISupports *, JS_GetPrivate(mContext, aTarget));
01462       nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper = do_QueryInterface(priv);
01463       if (xpcWrapper) {
01464         content = do_QueryWrappedNative(xpcWrapper);
01465       }
01466     }
01467     if (content) {
01468       // XXXbz XBL2/sXBL issue
01469       nsIDocument* ownerDoc = content->GetOwnerDoc();
01470       if (ownerDoc) {
01471         nsIScriptGlobalObject* global = ownerDoc->GetScriptGlobalObject();
01472         if (global) {
01473           nsIScriptContext* context = global->GetContext();
01474           if (context && context != this) {
01475             JSContext* cx =
01476               NS_STATIC_CAST(JSContext*, context->GetNativeContext());
01477             rv = stack->Push(cx);
01478             if (NS_SUCCEEDED(rv)) {
01479               rv = sSecurityManager->CheckFunctionAccess(cx, aHandler,
01480                                                          aTarget);
01481               // Here we lose no matter what; we don't want to leave the wrong
01482               // cx on the stack.  I guess default to leaving mContext, to
01483               // cover those cases when we really do have a different context
01484               // for the handler and the node.  That's probably safer.
01485               if (NS_FAILED(stack->Pop(nsnull))) {
01486                 return NS_ERROR_FAILURE;
01487               }
01488             }
01489           }
01490         }
01491       }
01492     }
01493   }
01494 
01495   nsJSContext::TerminationFuncHolder holder(this);
01496 
01497   if (NS_SUCCEEDED(rv)) {
01498     jsval funval = OBJECT_TO_JSVAL(aHandler);
01499     PRBool ok = ::JS_CallFunctionValue(mContext, aTarget, funval, argc, argv,
01500                                        rval);
01501 
01502     if (!ok) {
01503       // Tell XPConnect about any pending exceptions. This is needed
01504       // to avoid dropping JS exceptions in case we got here through
01505       // nested calls through XPConnect.
01506 
01507       nsContentUtils::NotifyXPCIfExceptionPending(mContext);
01508 
01509       // Don't pass back results from failed calls.
01510       *rval = JSVAL_VOID;
01511 
01512       // Tell the caller that the handler threw an error.
01513       rv = NS_ERROR_FAILURE;
01514     }
01515   }
01516 
01517   if (NS_FAILED(stack->Pop(nsnull)))
01518     return NS_ERROR_FAILURE;
01519 
01520   // Need to lock, since ScriptEvaluated can GC.
01521   PRBool locked = PR_FALSE;
01522   if (NS_SUCCEEDED(rv) && JSVAL_IS_GCTHING(*rval)) {
01523     locked = ::JS_LockGCThing(mContext, JSVAL_TO_GCTHING(*rval));
01524     if (!locked) {
01525       rv = NS_ERROR_OUT_OF_MEMORY;
01526     }
01527   }
01528 
01529   // ScriptEvaluated needs to come after we pop the stack
01530   ScriptEvaluated(PR_TRUE);
01531 
01532   if (locked) {
01533     ::JS_UnlockGCThing(mContext, JSVAL_TO_GCTHING(*rval));
01534   }
01535 
01536   return rv;
01537 }
01538 
01539 nsresult
01540 nsJSContext::BindCompiledEventHandler(void *aTarget, nsIAtom *aName,
01541                                       void *aHandler)
01542 {
01543   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
01544 
01545   const char *charName = AtomToEventHandlerName(aName);
01546 
01547   JSObject *funobj = (JSObject*) aHandler;
01548   JSObject *target = (JSObject*) aTarget;
01549 
01550   nsresult rv;
01551 
01552   // Push our JSContext on our thread's context stack, in case native code
01553   // called from JS calls back into JS via XPConnect.
01554   nsCOMPtr<nsIJSContextStack> stack =
01555            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01556   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
01557     return NS_ERROR_FAILURE;
01558   }
01559 
01560   // Make sure the handler function is parented by its event target object
01561   if (funobj && ::JS_GetParent(mContext, funobj) != target) {
01562     funobj = ::JS_CloneFunctionObject(mContext, funobj, target);
01563     if (!funobj)
01564       rv = NS_ERROR_OUT_OF_MEMORY;
01565   }
01566 
01567   if (NS_SUCCEEDED(rv) &&
01568       !::JS_DefineProperty(mContext, target, charName,
01569                            OBJECT_TO_JSVAL(funobj), nsnull, nsnull,
01570                            JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
01571     rv = NS_ERROR_FAILURE;
01572   }
01573 
01574   if (NS_FAILED(stack->Pop(nsnull)) && NS_SUCCEEDED(rv)) {
01575     rv = NS_ERROR_FAILURE;
01576   }
01577 
01578   return rv;
01579 }
01580 
01581 void
01582 nsJSContext::SetDefaultLanguageVersion(const char* aVersion)
01583 {
01584   ::JS_SetVersion(mContext, ::JS_StringToVersion(aVersion));
01585 }
01586 
01587 nsIScriptGlobalObject *
01588 nsJSContext::GetGlobalObject()
01589 {
01590   JSObject *global = ::JS_GetGlobalObject(mContext);
01591 
01592   if (!global) {
01593     NS_WARNING("Context has no global.");
01594     return nsnull;
01595   }
01596 
01597   JSClass *c = JS_GET_CLASS(mContext, global);
01598 
01599   if (!c || ((~c->flags) & (JSCLASS_HAS_PRIVATE |
01600                             JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
01601     NS_WARNING("Global is not an nsISupports.");
01602     return nsnull;
01603   }
01604 
01605   nsCOMPtr<nsIScriptGlobalObject> sgo;
01606   nsISupports *priv =
01607     (nsISupports *)::JS_GetPrivate(mContext, global);
01608 
01609   nsCOMPtr<nsIXPConnectWrappedNative> wrapped_native =
01610     do_QueryInterface(priv);
01611 
01612   if (wrapped_native) {
01613     // The global object is a XPConnect wrapped native, the native in
01614     // the wrapper might be the nsIScriptGlobalObject
01615 
01616     sgo = do_QueryWrappedNative(wrapped_native);
01617   } else {
01618     sgo = do_QueryInterface(priv);
01619   }
01620 
01621   // This'll return a pointer to something we're about to release, but
01622   // that's ok, the JS object will hold it alive long enough.
01623   return sgo;
01624 }
01625 
01626 void *
01627 nsJSContext::GetNativeContext()
01628 {
01629   return mContext;
01630 }
01631 
01632 const JSClass* NS_DOMClassInfo_GetXPCNativeWrapperClass();
01633 void NS_DOMClassInfo_SetXPCNativeWrapperClass(JSClass* aClass);
01634 
01635 nsresult
01636 nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject)
01637 {
01638   // Make sure callers of this use
01639   // WillInitializeContext/DidInitializeContext around this call.
01640   NS_ENSURE_TRUE(!mIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
01641 
01642   if (!mContext)
01643     return NS_ERROR_OUT_OF_MEMORY;
01644 
01645   InvalidateContextAndWrapperCache();
01646 
01647   nsresult rv;
01648 
01649   if (!gNameSpaceManager) {
01650     gNameSpaceManager = new nsScriptNameSpaceManager;
01651     NS_ENSURE_TRUE(gNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
01652 
01653     rv = gNameSpaceManager->Init();
01654     NS_ENSURE_SUCCESS(rv, rv);
01655   }
01656 
01657   ::JS_SetErrorReporter(mContext, NS_ScriptErrorReporter);
01658 
01659   if (!aGlobalObject) {
01660     // If we don't get a global object then there's nothing more to do here.
01661 
01662     return NS_OK;
01663   }
01664 
01665   nsIXPConnect *xpc = nsContentUtils::XPConnect();
01666 
01667   JSObject *global = ::JS_GetGlobalObject(mContext);
01668 
01669   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
01670 
01671   // If there's already a global object in mContext we won't tell
01672   // XPConnect to wrap aGlobalObject since it's already wrapped.
01673 
01674   if (!global) {
01675     nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aGlobalObject));
01676     PRUint32 flags = 0;
01677     
01678     if (chromeWindow) {
01679       // Flag this object and scripts compiled against it as "system", for
01680       // optional automated XPCNativeWrapper construction when chrome views
01681       // a content DOM.
01682       flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
01683 
01684       // Always enable E4X for XUL and other chrome content -- there is no
01685       // need to preserve the <!-- script hiding hack from JS-in-HTML daze
01686       // (introduced in 1995 for graceful script degradation in Netscape 1,
01687       // Mosaic, and other pre-JS browsers).
01688       ::JS_SetOptions(mContext, ::JS_GetOptions(mContext) | JSOPTION_XML);
01689     }
01690 
01691     rv = xpc->InitClassesWithNewWrappedGlobal(mContext, aGlobalObject,
01692                                               NS_GET_IID(nsISupports),
01693                                               flags,
01694                                               getter_AddRefs(holder));
01695     NS_ENSURE_SUCCESS(rv, rv);
01696 
01697     // Now check whether we need to grab a pointer to the
01698     // XPCNativeWrapper class
01699     if (!NS_DOMClassInfo_GetXPCNativeWrapperClass()) {
01700       rv = FindXPCNativeWrapperClass(holder);
01701       NS_ENSURE_SUCCESS(rv, rv);
01702     }
01703   } else {
01704     // If there's already a global object in mContext we're called
01705     // after ::JS_ClearScope() was called. We'll have to tell
01706     // XPConnect to re-initialize the global object to do things like
01707     // define the Components object on the global again and forget all
01708     // old prototypes in this scope.
01709     rv = xpc->InitClasses(mContext, global);
01710     NS_ENSURE_SUCCESS(rv, rv);
01711 
01712     nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(aGlobalObject));
01713 
01714     if (ci) {
01715       rv = xpc->WrapNative(mContext, global, aGlobalObject,
01716                            NS_GET_IID(nsISupports),
01717                            getter_AddRefs(holder));
01718       NS_ENSURE_SUCCESS(rv, rv);
01719 
01720       nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(holder));
01721       NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
01722 
01723       rv = wrapper->RefreshPrototype();
01724       NS_ENSURE_SUCCESS(rv, rv);
01725     }
01726   }
01727 
01728   // Hold a strong reference to the wrapper for the global to avoid
01729   // rooting and unrooting the global object every time its AddRef()
01730   // or Release() methods are called
01731   mGlobalWrapperRef = holder;
01732 
01733   holder->GetJSObject(&global);
01734 
01735   rv = InitClasses(global); // this will complete global object initialization
01736   NS_ENSURE_SUCCESS(rv, rv);
01737 
01738   return rv;
01739 }
01740 
01741 nsresult
01742 nsJSContext::InitializeExternalClasses()
01743 {
01744   NS_ENSURE_TRUE(gNameSpaceManager, NS_ERROR_NOT_INITIALIZED);
01745 
01746   return gNameSpaceManager->InitForContext(this);
01747 }
01748 
01749 nsresult
01750 nsJSContext::InitializeLiveConnectClasses(JSObject *aGlobalObj)
01751 {
01752   nsresult rv = NS_OK;
01753 
01754 #ifdef OJI
01755   nsCOMPtr<nsIJVMManager> jvmManager =
01756     do_GetService(nsIJVMManager::GetCID(), &rv);
01757 
01758   if (NS_SUCCEEDED(rv) && jvmManager) {
01759     PRBool javaEnabled = PR_FALSE;
01760 
01761     rv = jvmManager->GetJavaEnabled(&javaEnabled);
01762 
01763     if (NS_SUCCEEDED(rv) && javaEnabled) {
01764       nsCOMPtr<nsILiveConnectManager> liveConnectManager =
01765         do_QueryInterface(jvmManager);
01766 
01767       if (liveConnectManager) {
01768         rv = liveConnectManager->InitLiveConnectClasses(mContext, aGlobalObj);
01769       }
01770     }
01771   }
01772 #endif /* OJI */
01773 
01774   // return all is well until things are stable.
01775   return NS_OK;
01776 }
01777 
01778 nsresult
01779 nsJSContext::FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder)
01780 {
01781   NS_ASSERTION(!NS_DOMClassInfo_GetXPCNativeWrapperClass(),
01782                "Why was this called?");
01783 
01784   JSObject *globalObj;
01785   aHolder->GetJSObject(&globalObj);
01786   NS_ASSERTION(globalObj, "Must have global by now!");
01787       
01788   const char* arg = "arg";
01789   NS_NAMED_LITERAL_STRING(body, "return new XPCNativeWrapper(arg);");
01790 
01791   // Can't use CompileFunction() here because our principal isn't
01792   // inited yet and a null principal makes it fail.
01793   JSFunction *fun =
01794     ::JS_CompileUCFunction(mContext,
01795                            globalObj,
01796                            "_XPCNativeWrapperCtor",
01797                            1, &arg,
01798                            (jschar*)body.get(),
01799                            body.Length(),
01800                            "javascript:return new XPCNativeWrapper(arg);",
01801                            1 // lineno
01802                            );
01803   NS_ENSURE_TRUE(fun, NS_ERROR_FAILURE);
01804 
01805   jsval globalVal = OBJECT_TO_JSVAL(globalObj);
01806   jsval wrapper;
01807       
01808   JSBool ok = ::JS_CallFunction(mContext, globalObj, fun,
01809                                 1, &globalVal, &wrapper);
01810   if (!ok) {
01811     // No need to notify about pending exceptions here; we don't
01812     // expect any other than out of memory, really.
01813     return NS_ERROR_FAILURE;
01814   }
01815 
01816   NS_ASSERTION(JSVAL_IS_OBJECT(wrapper), "This should be an object!");
01817 
01818   NS_DOMClassInfo_SetXPCNativeWrapperClass(
01819     ::JS_GetClass(mContext, JSVAL_TO_OBJECT(wrapper)));
01820   return NS_OK;
01821 }
01822 
01823 static JSPropertySpec OptionsProperties[] = {
01824   {"strict",    JSOPTION_STRICT,    JSPROP_ENUMERATE | JSPROP_PERMANENT},
01825   {"werror",    JSOPTION_WERROR,    JSPROP_ENUMERATE | JSPROP_PERMANENT},
01826   {0}
01827 };
01828 
01829 static JSBool JS_DLL_CALLBACK
01830 GetOptionsProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
01831 {
01832   if (JSVAL_IS_INT(id)) {
01833     uint32 optbit = (uint32) JSVAL_TO_INT(id);
01834     if ((optbit & (optbit - 1)) == 0 && optbit <= JSOPTION_WERROR)
01835       *vp = (JS_GetOptions(cx) & optbit) ? JSVAL_TRUE : JSVAL_FALSE;
01836   }
01837   return JS_TRUE;
01838 }
01839 
01840 static JSBool JS_DLL_CALLBACK
01841 SetOptionsProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
01842 {
01843   if (JSVAL_IS_INT(id)) {
01844     uint32 optbit = (uint32) JSVAL_TO_INT(id);
01845 
01846     // Don't let options other than strict and werror be set -- it would be
01847     // bad if web page script could clear JSOPTION_PRIVATE_IS_NSISUPPORTS!
01848     if ((optbit & (optbit - 1)) == 0 && optbit <= JSOPTION_WERROR) {
01849       JSBool optval;
01850       if (! ::JS_ValueToBoolean(cx, *vp, &optval))
01851         return JS_FALSE;
01852 
01853       uint32 optset = ::JS_GetOptions(cx);
01854       if (optval)
01855         optset |= optbit;
01856       else
01857         optset &= ~optbit;
01858       ::JS_SetOptions(cx, optset);
01859     }
01860   }
01861   return JS_TRUE;
01862 }
01863 
01864 static JSClass OptionsClass = {
01865   "JSOptions",
01866   0,
01867   JS_PropertyStub, JS_PropertyStub, GetOptionsProperty, SetOptionsProperty,
01868   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
01869 };
01870 
01871 #ifdef NS_TRACE_MALLOC
01872 
01873 #include <errno.h>              // XXX assume Linux if NS_TRACE_MALLOC
01874 #include <fcntl.h>
01875 #ifdef XP_UNIX
01876 #include <unistd.h>
01877 #endif
01878 #ifdef XP_WIN32
01879 #include <io.h>
01880 #endif
01881 #include "nsTraceMalloc.h"
01882 
01883 static JSBool
01884 TraceMallocDisable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01885 {
01886     NS_TraceMallocDisable();
01887     return JS_TRUE;
01888 }
01889 
01890 static JSBool
01891 TraceMallocEnable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01892 {
01893     NS_TraceMallocEnable();
01894     return JS_TRUE;
01895 }
01896 
01897 static JSBool
01898 TraceMallocOpenLogFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01899 {
01900     int fd;
01901     JSString *str;
01902     char *filename;
01903 
01904     if (argc == 0) {
01905         fd = -1;
01906     } else {
01907         str = JS_ValueToString(cx, argv[0]);
01908         if (!str)
01909             return JS_FALSE;
01910         filename = JS_GetStringBytes(str);
01911         fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
01912         if (fd < 0) {
01913             JS_ReportError(cx, "can't open %s: %s", filename, strerror(errno));
01914             return JS_FALSE;
01915         }
01916     }
01917     *rval = INT_TO_JSVAL(fd);
01918     return JS_TRUE;
01919 }
01920 
01921 static JSBool
01922 TraceMallocChangeLogFD(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01923 {
01924     int32 fd, oldfd;
01925 
01926     if (argc == 0) {
01927         oldfd = -1;
01928     } else {
01929         if (!JS_ValueToECMAInt32(cx, argv[0], &fd))
01930             return JS_FALSE;
01931         oldfd = NS_TraceMallocChangeLogFD(fd);
01932         if (oldfd == -2) {
01933             JS_ReportOutOfMemory(cx);
01934             return JS_FALSE;
01935         }
01936     }
01937     *rval = INT_TO_JSVAL(oldfd);
01938     return JS_TRUE;
01939 }
01940 
01941 static JSBool
01942 TraceMallocCloseLogFD(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01943 {
01944     int32 fd;
01945 
01946     if (argc == 0)
01947         return JS_TRUE;
01948     if (!JS_ValueToECMAInt32(cx, argv[0], &fd))
01949         return JS_FALSE;
01950     NS_TraceMallocCloseLogFD((int) fd);
01951     return JS_TRUE;
01952 }
01953 
01954 static JSBool
01955 TraceMallocLogTimestamp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01956 {
01957     JSString *str;
01958     const char *caption;
01959 
01960     str = JS_ValueToString(cx, argv[0]);
01961     if (!str)
01962         return JS_FALSE;
01963     caption = JS_GetStringBytes(str);
01964     NS_TraceMallocLogTimestamp(caption);
01965     return JS_TRUE;
01966 }
01967 
01968 static JSBool
01969 TraceMallocDumpAllocations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01970 {
01971     JSString *str;
01972     const char *pathname;
01973 
01974     str = JS_ValueToString(cx, argv[0]);
01975     if (!str)
01976         return JS_FALSE;
01977     pathname = JS_GetStringBytes(str);
01978     if (NS_TraceMallocDumpAllocations(pathname) < 0) {
01979         JS_ReportError(cx, "can't dump to %s: %s", pathname, strerror(errno));
01980         return JS_FALSE;
01981     }
01982     return JS_TRUE;
01983 }
01984 
01985 static JSFunctionSpec TraceMallocFunctions[] = {
01986     {"TraceMallocDisable",         TraceMallocDisable,         0, 0, 0},
01987     {"TraceMallocEnable",          TraceMallocEnable,          0, 0, 0},
01988     {"TraceMallocOpenLogFile",     TraceMallocOpenLogFile,     1, 0, 0},
01989     {"TraceMallocChangeLogFD",     TraceMallocChangeLogFD,     1, 0, 0},
01990     {"TraceMallocCloseLogFD",      TraceMallocCloseLogFD,      1, 0, 0},
01991     {"TraceMallocLogTimestamp",    TraceMallocLogTimestamp,    1, 0, 0},
01992     {"TraceMallocDumpAllocations", TraceMallocDumpAllocations, 1, 0, 0},
01993     {nsnull,                       nsnull,                     0, 0, 0}
01994 };
01995 
01996 #endif /* NS_TRACE_MALLOC */
01997 
01998 #ifdef MOZ_JPROF
01999 
02000 #include <signal.h>
02001 
02002 inline PRBool
02003 IsJProfAction(struct sigaction *action)
02004 {
02005     return (action->sa_sigaction &&
02006             action->sa_flags == SA_RESTART | SA_SIGINFO);
02007 }
02008 
02009 static JSBool
02010 JProfStartProfiling(JSContext *cx, JSObject *obj,
02011                     uintN argc, jsval *argv, jsval *rval)
02012 {
02013     // Figure out whether we're dealing with SIGPROF, SIGALRM, or
02014     // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
02015     // JP_RTC_HZ)
02016     struct sigaction action;
02017 
02018     sigaction(SIGALRM, nsnull, &action);
02019     if (IsJProfAction(&action)) {
02020         printf("Beginning real-time jprof profiling.\n");
02021         raise(SIGALRM);
02022         return JS_TRUE;
02023     }
02024 
02025     sigaction(SIGPROF, nsnull, &action);
02026     if (IsJProfAction(&action)) {
02027         printf("Beginning process-time jprof profiling.\n");
02028         raise(SIGPROF);
02029         return JS_TRUE;
02030     }
02031 
02032     sigaction(SIGPOLL, nsnull, &action);
02033     if (IsJProfAction(&action)) {
02034         printf("Beginning rtc-based jprof profiling.\n");
02035         raise(SIGPOLL);
02036         return JS_TRUE;
02037     }
02038 
02039     printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
02040     return JS_TRUE;
02041 }
02042 
02043 static JSBool
02044 JProfStopProfiling(JSContext *cx, JSObject *obj,
02045                    uintN argc, jsval *argv, jsval *rval)
02046 {
02047     raise(SIGUSR1);
02048     printf("Stopped jprof profiling.\n");
02049     return JS_TRUE;
02050 }
02051 
02052 static JSFunctionSpec JProfFunctions[] = {
02053     {"JProfStartProfiling",        JProfStartProfiling,        0, 0, 0},
02054     {"JProfStopProfiling",         JProfStopProfiling,         0, 0, 0},
02055     {nsnull,                       nsnull,                     0, 0, 0}
02056 };
02057 
02058 #endif /* defined(MOZ_JPROF) */
02059 
02060 nsresult
02061 nsJSContext::InitClasses(JSObject *aGlobalObj)
02062 {
02063   nsresult rv = NS_OK;
02064 
02065   rv = InitializeExternalClasses();
02066   NS_ENSURE_SUCCESS(rv, rv);
02067 
02068   rv = InitializeLiveConnectClasses(aGlobalObj);
02069   NS_ENSURE_SUCCESS(rv, rv);
02070 
02071   // Initialize the options object and set default options in mContext
02072   JSObject *optionsObj = ::JS_DefineObject(mContext, aGlobalObj, "_options",
02073                                            &OptionsClass, nsnull, 0);
02074   if (optionsObj &&
02075       ::JS_DefineProperties(mContext, optionsObj, OptionsProperties)) {
02076     ::JS_SetOptions(mContext, mDefaultJSOptions);
02077   } else {
02078     rv = NS_ERROR_FAILURE;
02079   }
02080 
02081 #ifdef NS_TRACE_MALLOC
02082   // Attempt to initialize TraceMalloc functions
02083   ::JS_DefineFunctions(mContext, aGlobalObj, TraceMallocFunctions);
02084 #endif
02085 
02086 #ifdef MOZ_JPROF
02087   // Attempt to initialize JProf functions
02088   ::JS_DefineFunctions(mContext, aGlobalObj, JProfFunctions);
02089 #endif
02090 
02091   return rv;
02092 }
02093 
02094 void
02095 nsJSContext::WillInitializeContext()
02096 {
02097   mIsInitialized = PR_FALSE;
02098 }
02099 
02100 void
02101 nsJSContext::DidInitializeContext()
02102 {
02103   mIsInitialized = PR_TRUE;
02104 }
02105 
02106 PRBool
02107 nsJSContext::IsContextInitialized()
02108 {
02109   return mIsInitialized;
02110 }
02111 
02112 void
02113 nsJSContext::GC()
02114 {
02115   FireGCTimer();
02116 }
02117 
02118 void
02119 nsJSContext::ScriptEvaluated(PRBool aTerminated)
02120 {
02121   if (aTerminated && mTerminations) {
02122     // Make sure to null out mTerminations before doing anything that
02123     // might cause new termination funcs to be added!
02124     nsJSContext::TerminationFuncClosure* start = mTerminations;
02125     mTerminations = nsnull;
02126     
02127     for (nsJSContext::TerminationFuncClosure* cur = start;
02128          cur;
02129          cur = cur->mNext) {
02130       (*(cur->mTerminationFunc))(cur->mTerminationFuncArg);
02131     }
02132     delete start;
02133   }
02134 
02135   mNumEvaluations++;
02136 
02137 #ifdef JS_GC_ZEAL
02138   if (mContext->runtime->gcZeal >= 2) {
02139     ::JS_MaybeGC(mContext);
02140   } else
02141 #endif
02142   if (mNumEvaluations > 20) {
02143     mNumEvaluations = 0;
02144     ::JS_MaybeGC(mContext);
02145   }
02146 
02147   mBranchCallbackCount = 0;
02148   mBranchCallbackTime = LL_ZERO;
02149 }
02150 
02151 void
02152 nsJSContext::SetOwner(nsIScriptContextOwner* owner)
02153 {
02154   // The owner should not be addrefed!! We'll be told
02155   // when the owner goes away.
02156   mOwner = owner;
02157 }
02158 
02159 nsIScriptContextOwner *
02160 nsJSContext::GetOwner()
02161 {
02162   return mOwner;
02163 }
02164 
02165 nsresult
02166 nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc,
02167                                     nsISupports* aRef)
02168 {
02169   nsJSContext::TerminationFuncClosure* newClosure =
02170     new nsJSContext::TerminationFuncClosure(aFunc, aRef, mTerminations);
02171   if (!newClosure) {
02172     return NS_ERROR_OUT_OF_MEMORY;
02173   }
02174 
02175   mTerminations = newClosure;
02176   return NS_OK;
02177 }
02178 
02179 PRBool
02180 nsJSContext::GetScriptsEnabled()
02181 {
02182   return mScriptsEnabled;
02183 }
02184 
02185 void
02186 nsJSContext::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
02187 {
02188   mScriptsEnabled = aEnabled;
02189 
02190   nsIScriptGlobalObject *global = GetGlobalObject();
02191 
02192   if (global) {
02193     global->SetScriptsEnabled(aEnabled, aFireTimeouts);
02194   }
02195 }
02196 
02197 
02198 PRBool
02199 nsJSContext::GetProcessingScriptTag()
02200 {
02201   return mProcessingScriptTag;
02202 }
02203 
02204 void
02205 nsJSContext::SetProcessingScriptTag(PRBool aFlag)
02206 {
02207   mProcessingScriptTag = aFlag;
02208 }
02209 
02210 void
02211 nsJSContext::SetGCOnDestruction(PRBool aGCOnDestruction)
02212 {
02213   mGCOnDestruction = aGCOnDestruction;
02214 }
02215 
02216 NS_IMETHODIMP
02217 nsJSContext::ScriptExecuted()
02218 {
02219   ScriptEvaluated(PR_FALSE);
02220 
02221   return NS_OK;
02222 }
02223 
02224 NS_IMETHODIMP
02225 nsJSContext::PreserveWrapper(nsIXPConnectWrappedNative *aWrapper)
02226 {
02227   return nsDOMClassInfo::PreserveNodeWrapper(aWrapper);
02228 }
02229 
02230 NS_IMETHODIMP
02231 nsJSContext::Notify(nsITimer *timer)
02232 {
02233   NS_ASSERTION(mContext, "No context in nsJSContext::Notify()!");
02234 
02235   ::JS_GC(mContext);
02236 
02237   sReadyForGC = PR_TRUE;
02238 
02239   NS_RELEASE(sGCTimer);
02240   return NS_OK;
02241 }
02242 
02243 void
02244 nsJSContext::FireGCTimer()
02245 {
02246   if (sGCTimer) {
02247     // There's already a timer for GC'ing, just clear newborn roots
02248     // and return
02249 
02250     ::JS_ClearNewbornRoots(mContext);
02251 
02252     return;
02253   }
02254 
02255   CallCreateInstance("@mozilla.org/timer;1", &sGCTimer);
02256 
02257   if (!sGCTimer) {
02258     NS_WARNING("Failed to create timer");
02259 
02260     ::JS_GC(mContext);
02261 
02262     return;
02263   }
02264 
02265   static PRBool first = PR_TRUE;
02266 
02267   sGCTimer->InitWithCallback(this,
02268                              first ? NS_FIRST_GC_DELAY : NS_GC_DELAY,
02269                              nsITimer::TYPE_ONE_SHOT);
02270 
02271   first = PR_FALSE;
02272 }
02273 
02274 static JSBool JS_DLL_CALLBACK
02275 DOMGCCallback(JSContext *cx, JSGCStatus status)
02276 {
02277   JSBool result = gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE;
02278 
02279   if (status == JSGC_BEGIN && PR_GetCurrentThread() != gDOMThread)
02280     return JS_FALSE;
02281 
02282   // XPCJSRuntime::GCCallback does marking from the JSGC_MARK_END callback.
02283   // we need to call EndGCMark *after* marking is finished.
02284   // XXX This relies on our callback being registered after
02285   // XPCJSRuntime's, although if they were registered the other way
02286   // around the ordering there would be correct.
02287   if (status == JSGC_MARK_END)
02288     nsDOMClassInfo::EndGCMark();
02289 
02290   return result;
02291 }
02292 
02293 //static
02294 void
02295 nsJSEnvironment::Startup()
02296 {
02297   // initialize all our statics, so that we can restart XPCOM
02298   sGCTimer = nsnull;
02299   sReadyForGC = PR_FALSE;
02300   gNameSpaceManager = nsnull;
02301   sRuntimeService = nsnull;
02302   sRuntime = nsnull;
02303   gDOMThread = nsnull;
02304   gOldJSGCCallback = nsnull;
02305   sIsInitialized = PR_FALSE;
02306   sDidShutdown = PR_FALSE;
02307   sContextCount = 0;
02308   sSecurityManager = nsnull;
02309   gCollation = nsnull;
02310 }
02311 
02312 JS_STATIC_DLL_CALLBACK(JSPrincipals *)
02313 ObjectPrincipalFinder(JSContext *cx, JSObject *obj)
02314 {
02315   if (!sSecurityManager)
02316     return nsnull;
02317 
02318   nsCOMPtr<nsIPrincipal> principal;
02319   nsresult rv =
02320     sSecurityManager->GetObjectPrincipal(cx, obj,
02321                                          getter_AddRefs(principal));
02322 
02323   if (NS_FAILED(rv) || !principal) {
02324     return nsnull;
02325   }
02326 
02327   JSPrincipals *jsPrincipals = nsnull;
02328   principal->GetJSPrincipals(cx, &jsPrincipals);
02329 
02330   // nsIPrincipal::GetJSPrincipals() returns a strong reference to the
02331   // JS principals, but the caller of this function expects a weak
02332   // reference. So we need to release here.
02333 
02334   JSPRINCIPALS_DROP(cx, jsPrincipals);
02335 
02336   return jsPrincipals;
02337 }
02338 
02339 static int PR_CALLBACK
02340 MaxScriptRunTimePrefChangedCallback(const char *aPrefName, void *aClosure)
02341 {
02342   // Default limit on script run time to 10 seconds. 0 means let
02343   // scripts run forever.
02344   PRBool isChromePref =
02345     strcmp(aPrefName, "dom.max_chrome_script_run_time") == 0;
02346   PRInt32 time = nsContentUtils::GetIntPref(aPrefName, isChromePref ? 20 : 10);
02347 
02348   PRTime t;
02349   if (time <= 0) {
02350     // Let scripts run for a really, really long time.
02351     t = LL_INIT(0x40000000, 0);
02352   } else {
02353     t = time * PR_USEC_PER_SEC;
02354   }
02355 
02356   if (isChromePref) {
02357     sMaxChromeScriptRunTime = t;
02358   } else {
02359     sMaxScriptRunTime = t;
02360   }
02361 
02362   return 0;
02363 }
02364 
02365 // static
02366 nsresult
02367 nsJSEnvironment::Init()
02368 {
02369   if (sIsInitialized) {
02370     return NS_OK;
02371   }
02372 
02373   nsresult rv = CallGetService(kJSRuntimeServiceContractID, &sRuntimeService);
02374   // get the JSRuntime from the runtime svc, if possible
02375   NS_ENSURE_SUCCESS(rv, rv);
02376 
02377   rv = sRuntimeService->GetRuntime(&sRuntime);
02378   NS_ENSURE_SUCCESS(rv, rv);
02379 
02380   gDOMThread = PR_GetCurrentThread();
02381 
02382 #ifdef DEBUG
02383   // Let's make sure that our main thread is the same as the xpcom main thread.
02384   {
02385     nsCOMPtr<nsIThread> t;
02386     PRThread* mainThread;
02387     rv = nsIThread::GetMainThread(getter_AddRefs(t));
02388     NS_ASSERTION(NS_SUCCEEDED(rv) && t, "bad");
02389     rv = t->GetPRThread(&mainThread);
02390     NS_ASSERTION(NS_SUCCEEDED(rv) && mainThread == gDOMThread, "bad");
02391   }
02392 #endif
02393 
02394   NS_ASSERTION(!gOldJSGCCallback,
02395                "nsJSEnvironment initialized more than once");
02396 
02397   // Save the old GC callback to chain to it, for GC-observing generality.
02398   gOldJSGCCallback = ::JS_SetGCCallbackRT(sRuntime, DOMGCCallback);
02399 
02400   // No chaining to a pre-existing callback here, we own this problem space.
02401 #ifdef NS_DEBUG
02402   JSObjectPrincipalsFinder oldfop =
02403 #endif
02404     ::JS_SetObjectPrincipalsFinder(sRuntime, ObjectPrincipalFinder);
02405   NS_ASSERTION(!oldfop, " fighting over the findObjectPrincipals callback!");
02406 
02407   // Set these global xpconnect options...
02408   nsIXPConnect *xpc = nsContentUtils::XPConnect();
02409   xpc->SetCollectGarbageOnMainThreadOnly(PR_TRUE);
02410   xpc->SetDeferReleasesUntilAfterGarbageCollection(PR_TRUE);
02411 
02412 #ifdef OJI
02413   // Initialize LiveConnect.  XXXbe use contractid rather than GetCID
02414   // NOTE: LiveConnect is optional so initialisation will still succeed
02415   //       even if the service is not present.
02416   nsCOMPtr<nsILiveConnectManager> manager =
02417            do_GetService(nsIJVMManager::GetCID());
02418 
02419   // Should the JVM manager perhaps define methods for starting up
02420   // LiveConnect?
02421   if (manager) {
02422     PRBool started = PR_FALSE;
02423     rv = manager->StartupLiveConnect(sRuntime, started);
02424     // XXX Did somebody mean to check |rv| ?
02425   }
02426 #endif /* OJI */
02427 
02428   nsContentUtils::RegisterPrefCallback("dom.max_script_run_time",
02429                                        MaxScriptRunTimePrefChangedCallback,
02430                                        nsnull);
02431   MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull);
02432 
02433   nsContentUtils::RegisterPrefCallback("dom.max_chrome_script_run_time",
02434                                        MaxScriptRunTimePrefChangedCallback,
02435                                        nsnull);
02436   MaxScriptRunTimePrefChangedCallback("dom.max_chrome_script_run_time",
02437                                       nsnull);
02438 
02439   rv = CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &sSecurityManager);
02440 
02441   sIsInitialized = NS_SUCCEEDED(rv);
02442 
02443   return rv;
02444 }
02445 
02446 // static
02447 void nsJSEnvironment::ShutDown()
02448 {
02449   if (sGCTimer) {
02450     // We're being shut down, if we have a GC timer scheduled, cancel
02451     // it. The DOM factory will do one final GC once it's shut down.
02452 
02453     sGCTimer->Cancel();
02454 
02455     NS_RELEASE(sGCTimer);
02456   }
02457 
02458   delete gNameSpaceManager;
02459   gNameSpaceManager = nsnull;
02460 
02461   if (!sContextCount) {
02462     // We're being shutdown, and there are no more contexts
02463     // alive, release the JS runtime service and the security manager.
02464 
02465     if (sRuntimeService && sSecurityManager) {
02466       // No chaining to a pre-existing callback here, we own this problem space.
02467 #ifdef NS_DEBUG
02468       JSObjectPrincipalsFinder oldfop =
02469 #endif
02470         ::JS_SetObjectPrincipalsFinder(sRuntime, nsnull);
02471       NS_ASSERTION(oldfop == ObjectPrincipalFinder, " fighting over the findObjectPrincipals callback!");
02472     }
02473     NS_IF_RELEASE(sRuntimeService);
02474     NS_IF_RELEASE(sSecurityManager);
02475     NS_IF_RELEASE(gCollation);
02476     NS_IF_RELEASE(gDecoder);
02477   }
02478 
02479   sDidShutdown = PR_TRUE;
02480 }
02481 
02482 // static
02483 nsresult
02484 nsJSEnvironment::CreateNewContext(nsIScriptContext **aContext)
02485 {
02486   *aContext = new nsJSContext(sRuntime);
02487   NS_ENSURE_TRUE(*aContext, NS_ERROR_OUT_OF_MEMORY);
02488 
02489   NS_ADDREF(*aContext);
02490   return NS_OK;
02491 }
02492 
02493 nsresult
02494 NS_CreateScriptContext(nsIScriptGlobalObject *aGlobal,
02495                        nsIScriptContext **aContext)
02496 {
02497   nsresult rv = nsJSEnvironment::Init();
02498   NS_ENSURE_SUCCESS(rv, rv);
02499 
02500   nsCOMPtr<nsIScriptContext> scriptContext;
02501   rv = nsJSEnvironment::CreateNewContext(getter_AddRefs(scriptContext));
02502   NS_ENSURE_SUCCESS(rv, rv);
02503 
02504   scriptContext->WillInitializeContext();
02505 
02506   // Bind the script context and the global object
02507   rv = scriptContext->InitContext(aGlobal);
02508   NS_ENSURE_SUCCESS(rv, rv);
02509 
02510   scriptContext->DidInitializeContext();
02511 
02512   if (aGlobal) {
02513     aGlobal->SetContext(scriptContext);
02514   }
02515 
02516   *aContext = scriptContext;
02517 
02518   NS_ADDREF(*aContext);
02519 
02520   return rv;
02521 }
02522