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
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
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.
24 * Mark Hammond <mhammond@skippinet.com.au>
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.
38 * ***** END LICENSE BLOCK ***** */
41 #include "nsJSEnvironment.h"
42 #include "nsIScriptGlobalObject.h"
43 #include "nsIScriptObjectPrincipal.h"
44 #include "nsIDOMChromeWindow.h"
45 #include "nsPIDOMWindow.h"
46 #include "nsIDOMNode.h"
47 #include "nsIDOMElement.h"
48 #include "nsIDOMDocument.h"
49 #include "nsIDOMText.h"
50 #include "nsIDOMAttr.h"
51 #include "nsIDOMNamedNodeMap.h"
52 #include "nsIDOMNodeList.h"
53 #include "nsIDOMKeyEvent.h"
54 #include "nsIDOMHTMLImageElement.h"
55 #include "nsIDOMHTMLOptionElement.h"
56 #include "nsIScriptSecurityManager.h"
58 #include "nsIServiceManager.h"
59 #include "nsIXPConnect.h"
60 #include "nsIJSContextStack.h"
61 #include "nsIJSRuntimeService.h"
63 #include "nsISupportsPrimitives.h"
64 #include "nsReadableUtils.h"
65 #include "nsJSUtils.h"
66 #include "nsIDocShell.h"
67 #include "nsIDocShellTreeItem.h"
68 #include "nsPresContext.h"
69 #include "nsIConsoleService.h"
70 #include "nsIScriptError.h"
71 #include "nsIInterfaceRequestor.h"
72 #include "nsIInterfaceRequestorUtils.h"
73 #include "nsIPrompt.h"
74 #include "nsIObserverService.h"
75 #include "nsGUIEvent.h"
76 #include "nsThreadUtils.h"
79 #include "nsContentUtils.h"
80 #include "nsEventDispatcher.h"
81 #include "nsIContent.h"
82 #include "nsCycleCollector.h"
83 #include "nsNetUtil.h"
84 #include "nsXPCOMCIDInternal.h"
85 #include "nsIXULRuntime.h"
87 #include "nsDOMClassInfo.h"
89 #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
92 #include "nsIObjectInputStream.h"
93 #include "nsIObjectOutputStream.h"
94 #include "nsITimelineService.h"
95 #include "nsDOMScriptObjectHolder.h"
97 #include "WrapperFactory.h"
98 #include "nsGlobalWindow.h"
101 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
104 #include "AccessCheck.h"
106 #ifdef MOZ_JSDEBUGGER
107 #include "jsdIDebuggerService.h"
110 // Force PR_LOGGING so we can get JS strict warnings even in release builds
111 #define FORCE_PR_LOG 1
114 #include "prthread.h"
116 #include "mozilla/FunctionTimer.h"
118 const size_t gStackSize
= 8192;
121 static PRLogModuleInfo
* gJSDiagnostics
;
124 // Thank you Microsoft!
131 // The amount of time we wait between a request to GC (due to leaving
132 // a page) and doing the actual GC.
133 #define NS_GC_DELAY 2000 // ms
135 // The amount of time we wait until we force a GC in case the previous
136 // GC timer happened to fire while we were in the middle of loading a
137 // page (we'll GC once the page is loaded if that happens before this
138 // amount of time has passed).
139 #define NS_LOAD_IN_PROCESS_GC_DELAY 4000 // ms
141 // The amount of time we wait from the first request to GC to actually
142 // doing the first GC.
143 #define NS_FIRST_GC_DELAY 10000 // ms
145 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
147 // The max number of delayed cycle collects..
148 #define NS_MAX_DELAYED_CCOLLECT 45
149 // The max number of user interaction notifications in inactive state before
150 // we try to call cycle collector more aggressively.
151 #define NS_CC_SOFT_LIMIT_INACTIVE 6
152 // The max number of user interaction notifications in active state before
153 // we try to call cycle collector more aggressively.
154 #define NS_CC_SOFT_LIMIT_ACTIVE 12
155 // When higher probability MaybeCC is used, the number of sDelayedCCollectCount
156 // is multiplied with this number.
157 #define NS_PROBABILITY_MULTIPLIER 3
158 // Cycle collector is never called more often than every NS_MIN_CC_INTERVAL
159 // milliseconds. Exceptions are low memory situation and memory pressure
161 #define NS_MIN_CC_INTERVAL 10000 // ms
162 // If previous cycle collection collected more than this number of objects,
163 // the next collection will happen somewhat soon.
164 #define NS_COLLECTED_OBJECTS_LIMIT 5000
165 // CC will be called if GC has been called at least this number of times and
166 // there are at least NS_MIN_SUSPECT_CHANGES new suspected objects.
167 #define NS_MAX_GC_COUNT 5
168 #define NS_MIN_SUSPECT_CHANGES 10
169 // CC will be called if there are at least NS_MAX_SUSPECT_CHANGES new suspected
171 #define NS_MAX_SUSPECT_CHANGES 100
173 // if you add statics here, add them to the list in nsJSRuntime::Startup
175 static PRUint32 sDelayedCCollectCount
;
176 static PRUint32 sCCollectCount
;
177 static PRBool sUserIsActive
;
178 static PRTime sPreviousCCTime
;
179 static PRUint32 sCollectedObjectsCounts
;
180 static PRUint32 sSavedGCCount
;
181 static PRUint32 sCCSuspectChanges
;
182 static PRUint32 sCCSuspectedCount
;
183 static nsITimer
*sGCTimer
;
184 static PRBool sReadyForGC
;
186 // The number of currently pending document loads. This count isn't
187 // guaranteed to always reflect reality and can't easily as we don't
188 // have an easy place to know when a load ends or is interrupted in
189 // all cases. This counter also gets reset if we end up GC'ing while
190 // we're waiting for a slow page to load. IOW, this count may be 0
191 // even when there are pending loads.
192 static PRUint32 sPendingLoadCount
;
194 // Boolean that tells us whether or not the current GC timer
195 // (sGCTimer) was scheduled due to a GC timer firing while we were in
196 // the middle of loading a page.
197 static PRBool sLoadInProgressGCTimer
;
199 nsScriptNameSpaceManager
*gNameSpaceManager
;
201 static nsIJSRuntimeService
*sRuntimeService
;
202 JSRuntime
*nsJSRuntime::sRuntime
;
204 static const char kJSRuntimeServiceContractID
[] =
205 "@mozilla.org/js/xpc/RuntimeService;1";
207 static JSGCCallback gOldJSGCCallback
;
209 static PRBool sIsInitialized
;
210 static PRBool sDidShutdown
;
212 static PRInt32 sContextCount
;
214 static PRTime sMaxScriptRunTime
;
215 static PRTime sMaxChromeScriptRunTime
;
217 static nsIScriptSecurityManager
*sSecurityManager
;
219 // nsUserActivityObserver observes user-interaction-active and
220 // user-interaction-inactive notifications. It counts the number of
221 // notifications and if the number is bigger than NS_CC_SOFT_LIMIT_ACTIVE
222 // (in case the current notification is user-interaction-active) or
223 // NS_CC_SOFT_LIMIT_INACTIVE (current notification is user-interaction-inactive)
224 // MaybeCC is called with aHigherParameter set to PR_TRUE, otherwise PR_FALSE.
226 // When moving from active state to inactive, nsJSContext::IntervalCC() is
227 // called unless the timer related to page load is active.
229 class nsUserActivityObserver
: public nsIObserver
232 nsUserActivityObserver()
233 : mUserActivityCounter(0), mOldCCollectCount(0) {}
237 PRUint32 mUserActivityCounter
;
238 PRUint32 mOldCCollectCount
;
241 NS_IMPL_ISUPPORTS1(nsUserActivityObserver
, nsIObserver
)
244 nsUserActivityObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
245 const PRUnichar
* aData
)
247 if (mOldCCollectCount
!= sCCollectCount
) {
248 mOldCCollectCount
= sCCollectCount
;
249 // Cycle collector was called between user interaction notifications, so
250 // we can reset the counter.
251 mUserActivityCounter
= 0;
253 PRBool higherProbability
= PR_FALSE
;
254 ++mUserActivityCounter
;
255 if (!strcmp(aTopic
, "user-interaction-inactive")) {
257 printf("user-interaction-inactive\n");
260 sUserIsActive
= PR_FALSE
;
262 nsJSContext::IntervalCC();
266 higherProbability
= (mUserActivityCounter
> NS_CC_SOFT_LIMIT_INACTIVE
);
267 } else if (!strcmp(aTopic
, "user-interaction-active")) {
269 printf("user-interaction-active\n");
271 sUserIsActive
= PR_TRUE
;
272 higherProbability
= (mUserActivityCounter
> NS_CC_SOFT_LIMIT_ACTIVE
);
273 } else if (!strcmp(aTopic
, "xpcom-shutdown")) {
274 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
276 obs
->RemoveObserver(this, "user-interaction-active");
277 obs
->RemoveObserver(this, "user-interaction-inactive");
278 obs
->RemoveObserver(this, "xpcom-shutdown");
282 nsJSContext::MaybeCC(higherProbability
);
286 // nsCCMemoryPressureObserver observes the memory-pressure notifications
287 // and forces a cycle collection when it happens.
289 class nsCCMemoryPressureObserver
: public nsIObserver
296 NS_IMPL_ISUPPORTS1(nsCCMemoryPressureObserver
, nsIObserver
)
299 nsCCMemoryPressureObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
300 const PRUnichar
* aData
)
302 nsJSContext::CC(nsnull
);
306 /****************************************************************
307 ************************** AutoFree ****************************
308 ****************************************************************/
312 AutoFree(void *aPtr
) : mPtr(aPtr
) {
316 nsMemory::Free(mPtr
);
325 class nsAutoPoolRelease
{
327 nsAutoPoolRelease(JSArenaPool
*p
, void *m
) : mPool(p
), mMark(m
) {}
328 ~nsAutoPoolRelease() { JS_ARENA_RELEASE(mPool
, mMark
); }
334 // A utility function for script languages to call. Although it looks small,
335 // the use of nsIDocShell and nsPresContext triggers a huge number of
336 // dependencies that most languages would not otherwise need.
337 // XXXmarkh - This function is mis-placed!
339 NS_HandleScriptError(nsIScriptGlobalObject
*aScriptGlobal
,
340 nsScriptErrorEvent
*aErrorEvent
,
341 nsEventStatus
*aStatus
)
343 PRBool called
= PR_FALSE
;
344 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobal
));
345 nsIDocShell
*docShell
= win
? win
->GetDocShell() : nsnull
;
347 nsRefPtr
<nsPresContext
> presContext
;
348 docShell
->GetPresContext(getter_AddRefs(presContext
));
350 static PRInt32 errorDepth
; // Recursion prevention
353 if (presContext
&& errorDepth
< 2) {
354 // Dispatch() must be synchronous for the recursion block
355 // (errorDepth) to work.
356 nsEventDispatcher::Dispatch(win
, presContext
, aErrorEvent
, nsnull
,
365 class ScriptErrorEvent
: public nsRunnable
368 ScriptErrorEvent(nsIScriptGlobalObject
* aScriptGlobal
,
369 PRUint32 aLineNr
, PRUint32 aColumn
, PRUint32 aFlags
,
370 const nsAString
& aErrorMsg
,
371 const nsAString
& aFileName
,
372 const nsAString
& aSourceLine
,
373 PRBool aDispatchEvent
,
375 : mScriptGlobal(aScriptGlobal
), mLineNr(aLineNr
), mColumn(aColumn
),
376 mFlags(aFlags
), mErrorMsg(aErrorMsg
), mFileName(aFileName
),
377 mSourceLine(aSourceLine
), mDispatchEvent(aDispatchEvent
),
383 nsEventStatus status
= nsEventStatus_eIgnore
;
384 // First, notify the DOM that we have a script error.
385 if (mDispatchEvent
) {
386 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
387 nsIDocShell
* docShell
= win
? win
->GetDocShell() : nsnull
;
389 !JSREPORT_IS_WARNING(mFlags
) &&
390 !sHandlingScriptError
) {
391 sHandlingScriptError
= PR_TRUE
; // Recursion prevention
393 nsRefPtr
<nsPresContext
> presContext
;
394 docShell
->GetPresContext(getter_AddRefs(presContext
));
397 nsScriptErrorEvent
errorevent(PR_TRUE
, NS_LOAD_ERROR
);
399 errorevent
.fileName
= mFileName
.get();
401 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(win
));
402 NS_ENSURE_STATE(sop
);
403 nsIPrincipal
* p
= sop
->GetPrincipal();
406 PRBool sameOrigin
= mFileName
.IsVoid();
408 if (p
&& !sameOrigin
) {
409 nsCOMPtr
<nsIURI
> errorURI
;
410 NS_NewURI(getter_AddRefs(errorURI
), mFileName
);
412 // FIXME: Once error reports contain the origin of the
413 // error (principals) we should change this to do the
414 // security check based on the principals and not
415 // URIs. See bug 387476.
416 sameOrigin
= NS_SUCCEEDED(p
->CheckMayLoad(errorURI
, PR_FALSE
));
420 NS_NAMED_LITERAL_STRING(xoriginMsg
, "Script error.");
422 errorevent
.errorMsg
= mErrorMsg
.get();
423 errorevent
.lineNr
= mLineNr
;
425 NS_WARNING("Not same origin error!");
426 errorevent
.errorMsg
= xoriginMsg
.get();
427 errorevent
.lineNr
= 0;
428 // FIXME: once the principal of the script is not tied to
429 // the filename, we can stop using the post-redirect
430 // filename if we want and remove this line. Note that
431 // apparently we can't handle null filenames in the error
432 // event dispatching code.
433 static PRUnichar nullFilename
[] = { PRUnichar(0) };
434 errorevent
.fileName
= nullFilename
;
437 nsEventDispatcher::Dispatch(win
, presContext
, &errorevent
, nsnull
,
441 sHandlingScriptError
= PR_FALSE
;
445 if (status
!= nsEventStatus_eConsumeNoDefault
) {
446 // Make an nsIScriptError and populate it with information from
448 nsCOMPtr
<nsIScriptError
> errorObject
=
449 do_CreateInstance("@mozilla.org/scripterror;1");
451 if (errorObject
!= nsnull
) {
452 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
454 // Set category to chrome or content
455 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptPrincipal
=
456 do_QueryInterface(mScriptGlobal
);
457 NS_ASSERTION(scriptPrincipal
, "Global objects must implement "
458 "nsIScriptObjectPrincipal");
459 nsCOMPtr
<nsIPrincipal
> systemPrincipal
;
460 sSecurityManager
->GetSystemPrincipal(getter_AddRefs(systemPrincipal
));
461 const char * category
=
462 scriptPrincipal
->GetPrincipal() == systemPrincipal
463 ? "chrome javascript"
464 : "content javascript";
466 nsCOMPtr
<nsIScriptError2
> error2(do_QueryInterface(errorObject
));
468 rv
= error2
->InitWithWindowID(mErrorMsg
.get(), mFileName
.get(),
470 mLineNr
, mColumn
, mFlags
,
471 category
, mWindowID
);
473 rv
= errorObject
->Init(mErrorMsg
.get(), mFileName
.get(),
475 mLineNr
, mColumn
, mFlags
,
479 if (NS_SUCCEEDED(rv
)) {
480 nsCOMPtr
<nsIConsoleService
> consoleService
=
481 do_GetService(NS_CONSOLESERVICE_CONTRACTID
, &rv
);
482 if (NS_SUCCEEDED(rv
)) {
483 consoleService
->LogMessage(errorObject
);
492 nsCOMPtr
<nsIScriptGlobalObject
> mScriptGlobal
;
498 nsString mSourceLine
;
499 PRBool mDispatchEvent
;
502 static PRBool sHandlingScriptError
;
505 PRBool
ScriptErrorEvent::sHandlingScriptError
= PR_FALSE
;
507 // NOTE: This function could be refactored to use the above. The only reason
508 // it has not been done is that the code below only fills the error event
509 // after it has a good nsPresContext - whereas using the above function
510 // would involve always filling it. Is that a concern?
512 NS_ScriptErrorReporter(JSContext
*cx
,
514 JSErrorReport
*report
)
516 // We don't want to report exceptions too eagerly, but warnings in the
517 // absence of werror are swallowed whole, so report those now.
518 if (!JSREPORT_IS_WARNING(report
->flags
)) {
519 JSStackFrame
* fp
= nsnull
;
520 while ((fp
= JS_FrameIterator(cx
, &fp
))) {
521 if (JS_IsScriptFrame(cx
, fp
)) {
526 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
528 nsAXPCNativeCallContext
*cc
= nsnull
;
529 xpc
->GetCurrentNativeCallContext(&cc
);
531 nsAXPCNativeCallContext
*prev
= cc
;
532 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
534 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
535 lang
== nsAXPCNativeCallContext::LANG_JS
) {
543 // XXX this means we are not going to get error reports on non DOM contexts
544 nsIScriptContext
*context
= nsJSUtils::GetDynamicScriptContext(cx
);
546 // Note: we must do this before running any more code on cx (if cx is the
547 // dynamic script context).
548 ::JS_ClearPendingException(cx
);
551 nsIScriptGlobalObject
*globalObject
= context
->GetGlobalObject();
554 nsAutoString fileName
, msg
;
555 if (!report
->filename
) {
556 fileName
.SetIsVoid(PR_TRUE
);
558 fileName
.AssignWithConversion(report
->filename
);
561 const PRUnichar
*m
= reinterpret_cast<const PRUnichar
*>
567 if (msg
.IsEmpty() && message
) {
568 msg
.AssignWithConversion(message
);
572 /* We do not try to report Out Of Memory via a dom
573 * event because the dom event handler would encounter
574 * an OOM exception trying to process the event, and
575 * then we'd need to generate a new OOM event for that
576 * new OOM instance -- this isn't pretty.
578 nsAutoString sourceLine
;
579 sourceLine
.Assign(reinterpret_cast<const PRUnichar
*>(report
->uclinebuf
));
580 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(globalObject
);
581 PRUint64 windowID
= win
? win
->WindowID() : 0;
582 nsContentUtils::AddScriptRunner(
583 new ScriptErrorEvent(globalObject
, report
->lineno
,
584 report
->uctokenptr
- report
->uclinebuf
,
585 report
->flags
, msg
, fileName
, sourceLine
,
586 report
->errorNumber
!= JSMSG_OUT_OF_MEMORY
,
592 // Print it to stderr as well, for the benefit of those invoking
593 // mozilla with -console.
595 error
.Assign("JavaScript ");
596 if (JSREPORT_IS_STRICT(report
->flags
))
597 error
.Append("strict ");
598 if (JSREPORT_IS_WARNING(report
->flags
))
599 error
.Append("warning: ");
601 error
.Append("error: ");
602 error
.Append(report
->filename
);
603 error
.Append(", line ");
604 error
.AppendInt(report
->lineno
, 10);
606 if (report
->ucmessage
) {
607 AppendUTF16toUTF8(reinterpret_cast<const PRUnichar
*>(report
->ucmessage
),
610 error
.Append(message
);
613 fprintf(stderr
, "%s\n", error
.get());
619 gJSDiagnostics
= PR_NewLogModule("JSDiagnostics");
621 if (gJSDiagnostics
) {
622 PR_LOG(gJSDiagnostics
,
623 JSREPORT_IS_WARNING(report
->flags
) ? PR_LOG_WARNING
: PR_LOG_ERROR
,
624 ("file %s, line %u: %s\n%s%s",
625 report
->filename
, report
->lineno
, message
,
626 report
->linebuf
? report
->linebuf
: "",
628 report
->linebuf
[strlen(report
->linebuf
)-1] != '\n')
636 // A couple of useful functions to call when you're debugging.
638 JSObject2Win(JSContext
*cx
, JSObject
*obj
)
640 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
645 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
646 xpc
->GetWrappedNativeOfJSObject(cx
, obj
, getter_AddRefs(wrapper
));
648 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryWrappedNative(wrapper
);
650 return static_cast<nsGlobalWindow
*>
651 (static_cast<nsPIDOMWindow
*>(win
));
659 PrintWinURI(nsGlobalWindow
*win
)
662 printf("No window passed in.\n");
666 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(win
->GetExtantDocument());
668 printf("No document in the window.\n");
672 nsIURI
*uri
= doc
->GetDocumentURI();
674 printf("Document doesn't have a URI.\n");
680 printf("%s\n", spec
.get());
684 PrintWinCodebase(nsGlobalWindow
*win
)
687 printf("No window passed in.\n");
691 nsIPrincipal
*prin
= win
->GetPrincipal();
693 printf("Window doesn't have principals.\n");
697 nsCOMPtr
<nsIURI
> uri
;
698 prin
->GetURI(getter_AddRefs(uri
));
700 printf("No URI, maybe the system principal.\n");
706 printf("%s\n", spec
.get());
710 DumpString(const nsAString
&str
)
712 printf("%s\n", NS_ConvertUTF16toUTF8(str
).get());
716 static already_AddRefed
<nsIPrompt
>
717 GetPromptFromContext(nsJSContext
* ctx
)
719 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(ctx
->GetGlobalObject()));
720 NS_ENSURE_TRUE(win
, nsnull
);
722 nsIDocShell
*docShell
= win
->GetDocShell();
723 NS_ENSURE_TRUE(docShell
, nsnull
);
725 nsCOMPtr
<nsIInterfaceRequestor
> ireq(do_QueryInterface(docShell
));
726 NS_ENSURE_TRUE(ireq
, nsnull
);
728 // Get the nsIPrompt interface from the docshell
730 ireq
->GetInterface(NS_GET_IID(nsIPrompt
), (void**)&prompt
);
735 nsJSContext::DOMOperationCallback(JSContext
*cx
)
739 // Get the native context
740 nsJSContext
*ctx
= static_cast<nsJSContext
*>(::JS_GetContextPrivate(cx
));
743 // Can happen; see bug 355811
747 // XXX Save the operation callback time so we can restore it after the GC,
748 // because GCing can cause JS to run on our context, causing our
749 // ScriptEvaluated to be called, and clearing our operation callback time.
751 PRTime callbackTime
= ctx
->mOperationCallbackTime
;
752 PRTime modalStateTime
= ctx
->mModalStateTime
;
756 // Now restore the callback time and count, in case they got reset.
757 ctx
->mOperationCallbackTime
= callbackTime
;
758 ctx
->mModalStateTime
= modalStateTime
;
760 PRTime now
= PR_Now();
762 if (callbackTime
== 0) {
763 // Initialize mOperationCallbackTime to start timing how long the
765 ctx
->mOperationCallbackTime
= now
;
769 if (ctx
->mModalStateDepth
) {
770 // We're waiting on a modal dialog, nothing more to do here.
774 PRTime duration
= now
- callbackTime
;
776 // Check the amount of time this script has been running, or if the
777 // dialog is disabled.
778 JSObject
* global
= ::JS_GetGlobalForScopeChain(cx
);
779 PRBool isTrackingChromeCodeTime
=
780 global
&& xpc::AccessCheck::isChrome(global
->getCompartment());
781 if (duration
< (isTrackingChromeCodeTime
?
782 sMaxChromeScriptRunTime
: sMaxScriptRunTime
)) {
786 if (!nsContentUtils::IsSafeToRunScript()) {
787 // If it isn't safe to run script, then it isn't safe to bring up the
788 // prompt (since that will cause the event loop to spin). In this case
789 // (which is rare), we just stop the script... But report a warning so
790 // that developers have some idea of what went wrong.
792 JS_ReportWarning(cx
, "A long running script was terminated");
796 // If we get here we're most likely executing an infinite loop in JS,
797 // we'll tell the user about this and we'll give the user the option
798 // of stopping the execution of the script.
799 nsCOMPtr
<nsIPrompt
> prompt
= GetPromptFromContext(ctx
);
800 NS_ENSURE_TRUE(prompt
, JS_TRUE
);
802 // Check if we should offer the option to debug
803 JSStackFrame
* fp
= ::JS_GetScriptedCaller(cx
, NULL
);
804 PRBool debugPossible
= (fp
!= nsnull
&& cx
->debugHooks
&&
805 cx
->debugHooks
->debuggerHandler
!= nsnull
);
806 #ifdef MOZ_JSDEBUGGER
807 // Get the debugger service if necessary.
809 PRBool jsds_IsOn
= PR_FALSE
;
810 const char jsdServiceCtrID
[] = "@mozilla.org/js/jsd/debugger-service;1";
811 nsCOMPtr
<jsdIExecutionHook
> jsdHook
;
812 nsCOMPtr
<jsdIDebuggerService
> jsds
= do_GetService(jsdServiceCtrID
, &rv
);
814 // Check if there's a user for the debugger service that's 'on' for us
815 if (NS_SUCCEEDED(rv
)) {
816 jsds
->GetDebuggerHook(getter_AddRefs(jsdHook
));
817 jsds
->GetIsOn(&jsds_IsOn
);
820 // If there is a debug handler registered for this runtime AND
821 // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
822 // then something useful will be done with our request to debug.
823 debugPossible
= ((jsds_IsOn
&& (jsdHook
!= nsnull
)) || !jsds_IsOn
);
827 // Get localizable strings
828 nsXPIDLString title
, msg
, stopButton
, waitButton
, debugButton
, neverShowDlg
;
830 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
834 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
838 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
839 "WaitForScriptButton",
842 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
848 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
852 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
853 "KillScriptWithDebugMessage",
857 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
862 //GetStringFromName can return NS_OK and still give NULL string
863 if (NS_FAILED(rv
) || !title
|| !msg
|| !stopButton
|| !waitButton
||
864 (!debugButton
&& debugPossible
) || !neverShowDlg
) {
865 NS_ERROR("Failed to get localized strings.");
869 // Append file and line number information, if available
870 JSScript
*script
= fp
? ::JS_GetFrameScript(cx
, fp
) : nsnull
;
872 const char *filename
= ::JS_GetScriptFilename(cx
, script
);
874 nsXPIDLString scriptLocation
;
875 NS_ConvertUTF8toUTF16
filenameUTF16(filename
);
876 const PRUnichar
*formatParams
[] = { filenameUTF16
.get() };
877 rv
= nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
878 "KillScriptLocation",
882 if (NS_SUCCEEDED(rv
) && scriptLocation
) {
883 msg
.AppendLiteral("\n\n");
884 msg
.Append(scriptLocation
);
886 JSStackFrame
*fp
, *iterator
= nsnull
;
887 fp
= ::JS_FrameIterator(cx
, &iterator
);
889 jsbytecode
*pc
= ::JS_GetFramePC(cx
, fp
);
891 PRUint32 lineno
= ::JS_PCToLineNumber(cx
, script
, pc
);
893 msg
.AppendInt(lineno
);
900 PRInt32 buttonPressed
= 0; //In case user exits dialog by clicking X
901 PRBool neverShowDlgChk
= PR_FALSE
;
902 PRUint32 buttonFlags
= nsIPrompt::BUTTON_POS_1_DEFAULT
+
903 (nsIPrompt::BUTTON_TITLE_IS_STRING
*
904 (nsIPrompt::BUTTON_POS_0
+ nsIPrompt::BUTTON_POS_1
));
906 // Add a third button if necessary:
908 buttonFlags
+= nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_2
;
910 // Null out the operation callback while we're re-entering JS here.
911 ::JS_SetOperationCallback(cx
, nsnull
);
914 rv
= prompt
->ConfirmEx(title
, msg
, buttonFlags
, waitButton
, stopButton
,
915 debugButton
, neverShowDlg
, &neverShowDlgChk
,
918 ::JS_SetOperationCallback(cx
, DOMOperationCallback
);
920 if (NS_FAILED(rv
) || (buttonPressed
== 0)) {
921 // Allow the script to continue running
923 if (neverShowDlgChk
) {
924 nsIPrefBranch
*prefBranch
= nsContentUtils::GetPrefBranch();
927 prefBranch
->SetIntPref(isTrackingChromeCodeTime
?
928 "dom.max_chrome_script_run_time" :
929 "dom.max_script_run_time", 0);
933 ctx
->mOperationCallbackTime
= PR_Now();
936 else if ((buttonPressed
== 2) && debugPossible
) {
939 switch(cx
->debugHooks
->debuggerHandler(cx
, script
, ::JS_GetFramePC(cx
, fp
),
942 debuggerHandlerData
)) {
944 JS_SetFrameReturnValue(cx
, fp
, rval
);
947 JS_ClearPendingException(cx
);
950 JS_SetPendingException(cx
, rval
);
952 case JSTRAP_CONTINUE
:
958 JS_ClearPendingException(cx
);
963 nsJSContext::EnterModalState()
965 if (!mModalStateDepth
) {
966 mModalStateTime
= mOperationCallbackTime
? PR_Now() : 0;
972 nsJSContext::LeaveModalState()
974 if (!mModalStateDepth
) {
975 NS_ERROR("Uh, mismatched LeaveModalState() call!");
982 // If we're still in a modal dialog, or mOperationCallbackTime is still
983 // uninitialized, do nothing.
984 if (mModalStateDepth
|| !mOperationCallbackTime
) {
988 // If mOperationCallbackTime was set when we entered the first dialog
989 // (and mModalStateTime is thus non-zero), adjust mOperationCallbackTime
990 // to account for time spent in the dialog.
991 // If mOperationCallbackTime got set while the modal dialog was open,
992 // simply set mOperationCallbackTime to the closing time of the dialog so
993 // that we never adjust mOperationCallbackTime to be in the future.
994 if (mModalStateTime
) {
995 mOperationCallbackTime
+= PR_Now() - mModalStateTime
;
998 mOperationCallbackTime
= PR_Now();
1002 #define JS_OPTIONS_DOT_STR "javascript.options."
1004 static const char js_options_dot_str
[] = JS_OPTIONS_DOT_STR
;
1005 static const char js_strict_option_str
[] = JS_OPTIONS_DOT_STR
"strict";
1007 static const char js_strict_debug_option_str
[] = JS_OPTIONS_DOT_STR
"strict.debug";
1009 static const char js_werror_option_str
[] = JS_OPTIONS_DOT_STR
"werror";
1010 static const char js_relimit_option_str
[]= JS_OPTIONS_DOT_STR
"relimit";
1012 static const char js_zeal_option_str
[] = JS_OPTIONS_DOT_STR
"gczeal";
1014 static const char js_tracejit_content_str
[] = JS_OPTIONS_DOT_STR
"tracejit.content";
1015 static const char js_tracejit_chrome_str
[] = JS_OPTIONS_DOT_STR
"tracejit.chrome";
1016 static const char js_methodjit_content_str
[] = JS_OPTIONS_DOT_STR
"methodjit.content";
1017 static const char js_methodjit_chrome_str
[] = JS_OPTIONS_DOT_STR
"methodjit.chrome";
1018 static const char js_profiling_content_str
[] = JS_OPTIONS_DOT_STR
"jitprofiling.content";
1019 static const char js_profiling_chrome_str
[] = JS_OPTIONS_DOT_STR
"jitprofiling.chrome";
1022 nsJSContext::JSOptionChangedCallback(const char *pref
, void *data
)
1024 nsJSContext
*context
= reinterpret_cast<nsJSContext
*>(data
);
1025 PRUint32 oldDefaultJSOptions
= context
->mDefaultJSOptions
;
1026 PRUint32 newDefaultJSOptions
= oldDefaultJSOptions
;
1028 PRBool strict
= nsContentUtils::GetBoolPref(js_strict_option_str
);
1030 newDefaultJSOptions
|= JSOPTION_STRICT
;
1032 newDefaultJSOptions
&= ~JSOPTION_STRICT
;
1034 nsIScriptGlobalObject
*global
= context
->GetGlobalObject();
1035 // XXX should we check for sysprin instead of a chrome window, to make
1036 // XXX components be covered by the chrome pref instead of the content one?
1037 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(global
));
1039 PRBool useTraceJIT
= nsContentUtils::GetBoolPref(chromeWindow
?
1040 js_tracejit_chrome_str
:
1041 js_tracejit_content_str
);
1042 PRBool useMethodJIT
= nsContentUtils::GetBoolPref(chromeWindow
?
1043 js_methodjit_chrome_str
:
1044 js_methodjit_content_str
);
1045 PRBool useProfiling
= nsContentUtils::GetBoolPref(chromeWindow
?
1046 js_profiling_chrome_str
:
1047 js_profiling_content_str
);
1048 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService(XULRUNTIME_SERVICE_CONTRACTID
);
1050 PRBool safeMode
= PR_FALSE
;
1051 xr
->GetInSafeMode(&safeMode
);
1053 useTraceJIT
= PR_FALSE
;
1054 useMethodJIT
= PR_FALSE
;
1055 useProfiling
= PR_FALSE
;
1060 newDefaultJSOptions
|= JSOPTION_JIT
;
1062 newDefaultJSOptions
&= ~JSOPTION_JIT
;
1065 newDefaultJSOptions
|= JSOPTION_METHODJIT
;
1067 newDefaultJSOptions
&= ~JSOPTION_METHODJIT
;
1070 newDefaultJSOptions
|= JSOPTION_PROFILING
;
1072 newDefaultJSOptions
&= ~JSOPTION_PROFILING
;
1075 // In debug builds, warnings are enabled in chrome context if javascript.options.strict.debug is true
1076 PRBool strictDebug
= nsContentUtils::GetBoolPref(js_strict_debug_option_str
);
1077 // Note this callback is also called from context's InitClasses thus we don't
1078 // need to enable this directly from InitContext
1079 if (strictDebug
&& (newDefaultJSOptions
& JSOPTION_STRICT
) == 0) {
1081 newDefaultJSOptions
|= JSOPTION_STRICT
;
1085 PRBool werror
= nsContentUtils::GetBoolPref(js_werror_option_str
);
1087 newDefaultJSOptions
|= JSOPTION_WERROR
;
1089 newDefaultJSOptions
&= ~JSOPTION_WERROR
;
1091 PRBool relimit
= nsContentUtils::GetBoolPref(js_relimit_option_str
);
1093 newDefaultJSOptions
|= JSOPTION_RELIMIT
;
1095 newDefaultJSOptions
&= ~JSOPTION_RELIMIT
;
1097 if (newDefaultJSOptions
!= oldDefaultJSOptions
) {
1098 // Set options only if we used the old defaults; otherwise the page has
1099 // customized some via the options object and we defer to its wisdom.
1100 if (::JS_GetOptions(context
->mContext
) == oldDefaultJSOptions
)
1101 ::JS_SetOptions(context
->mContext
, newDefaultJSOptions
);
1103 // Save the new defaults for the next page load (InitContext).
1104 context
->mDefaultJSOptions
= newDefaultJSOptions
;
1108 PRInt32 zeal
= nsContentUtils::GetIntPref(js_zeal_option_str
, -1);
1110 ::JS_SetGCZeal(context
->mContext
, (PRUint8
)zeal
);
1116 nsJSContext::nsJSContext(JSRuntime
*aRuntime
)
1117 : mGCOnDestruction(PR_TRUE
),
1123 mDefaultJSOptions
= JSOPTION_PRIVATE_IS_NSISUPPORTS
| JSOPTION_ANONFUNFIX
;
1125 mContext
= ::JS_NewContext(aRuntime
, gStackSize
);
1127 ::JS_SetContextPrivate(mContext
, static_cast<nsIScriptContext
*>(this));
1129 // Preserve any flags the context callback might have set.
1130 mDefaultJSOptions
|= ::JS_GetOptions(mContext
);
1132 // Make sure the new context gets the default context options
1133 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
1135 // Watch for the JS boolean options
1136 nsContentUtils::RegisterPrefCallback(js_options_dot_str
,
1137 JSOptionChangedCallback
,
1140 ::JS_SetOperationCallback(mContext
, DOMOperationCallback
);
1142 xpc_LocalizeContext(mContext
);
1144 mIsInitialized
= PR_FALSE
;
1145 mTerminations
= nsnull
;
1146 mScriptsEnabled
= PR_TRUE
;
1147 mOperationCallbackTime
= 0;
1148 mModalStateTime
= 0;
1149 mModalStateDepth
= 0;
1150 mProcessingScriptTag
= PR_FALSE
;
1153 nsJSContext::~nsJSContext()
1156 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptContext
*>(this));
1158 NS_PRECONDITION(!mTerminations
, "Shouldn't have termination funcs by now");
1160 mGlobalObjectRef
= nsnull
;
1166 if (!sContextCount
&& sDidShutdown
) {
1167 // The last context is being deleted, and we're already in the
1168 // process of shutting down, release the JS runtime service, and
1169 // the security manager.
1171 NS_IF_RELEASE(sRuntimeService
);
1172 NS_IF_RELEASE(sSecurityManager
);
1177 nsJSContext::DestroyJSContext()
1182 // Clear our entry in the JSContext, bugzilla bug 66413
1183 ::JS_SetContextPrivate(mContext
, nsnull
);
1185 // Unregister our "javascript.options.*" pref-changed callback.
1186 nsContentUtils::UnregisterPrefCallback(js_options_dot_str
,
1187 JSOptionChangedCallback
,
1190 PRBool do_gc
= mGCOnDestruction
&& !sGCTimer
&& sReadyForGC
;
1192 // Let xpconnect destroy the JSContext when it thinks the time is right.
1193 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
1195 xpc
->ReleaseJSContext(mContext
, !do_gc
);
1197 ::JS_DestroyContext(mContext
);
1199 ::JS_DestroyContextNoGC(mContext
);
1204 // QueryInterface implementation for nsJSContext
1205 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext
)
1206 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSContext
)
1207 NS_ASSERTION(!tmp
->mContext
|| tmp
->mContext
->outstandingRequests
== 0,
1208 "Trying to unlink a context with outstanding requests.");
1209 tmp
->mIsInitialized
= PR_FALSE
;
1210 tmp
->mGCOnDestruction
= PR_FALSE
;
1211 tmp
->DestroyJSContext();
1212 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1213 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext
)
1214 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1215 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext
)
1216 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObjectRef
)
1217 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1218 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext
)
1219 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext
, tmp
->GetCCRefcnt())
1220 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalObjectRef
)
1221 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mContext");
1222 nsContentUtils::XPConnect()->NoteJSContext(tmp
->mContext
, cb
);
1223 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1225 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext
)
1226 NS_INTERFACE_MAP_ENTRY(nsIScriptContext
)
1227 NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal
)
1228 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify
)
1229 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIScriptContext
)
1230 NS_INTERFACE_MAP_END
1233 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSContext
, nsIScriptContext
)
1234 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSContext
, nsIScriptContext
)
1237 nsJSContext::GetCCRefcnt()
1239 nsrefcnt refcnt
= mRefCnt
.get();
1240 if (NS_LIKELY(mContext
))
1241 refcnt
+= mContext
->outstandingRequests
;
1246 nsJSContext::EvaluateStringWithValue(const nsAString
& aScript
,
1248 nsIPrincipal
*aPrincipal
,
1253 PRBool
* aIsUndefined
)
1255 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1256 __LINE__
, aURL
, aLineNo
);
1258 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1260 if (!mScriptsEnabled
) {
1262 *aIsUndefined
= PR_TRUE
;
1270 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1272 // Safety first: get an object representing the script's principals, i.e.,
1273 // the entities who signed this script, or the fully-qualified-domain-name
1274 // or "codebase" from which it was loaded.
1275 JSPrincipals
*jsprin
;
1276 nsIPrincipal
*principal
= aPrincipal
;
1278 nsIScriptGlobalObject
*global
= GetGlobalObject();
1280 return NS_ERROR_FAILURE
;
1281 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
1282 do_QueryInterface(global
, &rv
);
1284 return NS_ERROR_FAILURE
;
1285 principal
= objPrincipal
->GetPrincipal();
1287 return NS_ERROR_FAILURE
;
1290 principal
->GetJSPrincipals(mContext
, &jsprin
);
1292 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1294 PRBool ok
= PR_FALSE
;
1296 rv
= sSecurityManager
->CanExecuteScripts(mContext
, principal
, &ok
);
1297 if (NS_FAILED(rv
)) {
1298 JSPRINCIPALS_DROP(mContext
, jsprin
);
1299 return NS_ERROR_FAILURE
;
1302 // Push our JSContext on the current thread's context stack so JS called
1303 // from native code via XPConnect uses the right context. Do this whether
1304 // or not the SecurityManager said "ok", in order to simplify control flow
1305 // below where we pop before returning.
1306 nsCOMPtr
<nsIJSContextStack
> stack
=
1307 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1308 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1309 JSPRINCIPALS_DROP(mContext
, jsprin
);
1310 return NS_ERROR_FAILURE
;
1315 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1316 NS_ENSURE_SUCCESS(rv
, rv
);
1318 nsJSContext::TerminationFuncHolder
holder(this);
1320 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1321 // Since the caller is responsible for parsing the version strings, we just
1322 // check it isn't JSVERSION_UNKNOWN.
1323 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1325 JSAutoRequest
ar(mContext
);
1327 JSAutoEnterCompartment ac
;
1328 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1329 JSPRINCIPALS_DROP(mContext
, jsprin
);
1331 return NS_ERROR_FAILURE
;
1336 ok
= ::JS_EvaluateUCScriptForPrincipalsVersion(mContext
,
1337 (JSObject
*)aScopeObject
,
1339 (jschar
*)PromiseFlatString(aScript
).get(),
1344 JSVersion(aVersion
));
1349 // Tell XPConnect about any pending exceptions. This is needed
1350 // to avoid dropping JS exceptions in case we got here through
1351 // nested calls through XPConnect.
1353 ReportPendingException();
1357 // Whew! Finally done with these manually ref-counted things.
1358 JSPRINCIPALS_DROP(mContext
, jsprin
);
1360 // If all went well, convert val to a string (XXXbe unless undefined?).
1363 *aIsUndefined
= JSVAL_IS_VOID(val
);
1366 *static_cast<jsval
*>(aRetValue
) = val
;
1367 // XXX - nsScriptObjectHolder should be used once this method moves to
1368 // the new world order. However, use of 'jsval' appears to make this
1373 *aIsUndefined
= PR_TRUE
;
1377 sSecurityManager
->PopContextPrincipal(mContext
);
1379 // Pop here, after JS_ValueToString and any other possible evaluation.
1380 if (NS_FAILED(stack
->Pop(nsnull
)))
1381 rv
= NS_ERROR_FAILURE
;
1383 // ScriptEvaluated needs to come after we pop the stack
1384 ScriptEvaluated(PR_TRUE
);
1390 // Helper function to convert a jsval to an nsAString, and set
1391 // exception flags if the conversion fails.
1393 JSValueToAString(JSContext
*cx
, jsval val
, nsAString
*result
,
1394 PRBool
*isUndefined
)
1397 *isUndefined
= JSVAL_IS_VOID(val
);
1404 JSString
* jsstring
= ::JS_ValueToString(cx
, val
);
1410 const jschar
*chars
;
1411 chars
= ::JS_GetStringCharsAndLength(cx
, jsstring
, &length
);
1416 result
->Assign(chars
, length
);
1420 // We failed to convert val to a string. We're either OOM, or the
1421 // security manager denied access to .toString(), or somesuch, on
1422 // an object. Treat this case as if the result were undefined.
1427 *isUndefined
= PR_TRUE
;
1430 if (!::JS_IsExceptionPending(cx
)) {
1431 // JS_ValueToString()/JS_GetStringCharsAndLength returned null w/o an
1432 // exception pending. That means we're OOM.
1434 return NS_ERROR_OUT_OF_MEMORY
;
1440 nsIScriptObjectPrincipal
*
1441 nsJSContext::GetObjectPrincipal()
1443 nsCOMPtr
<nsIScriptObjectPrincipal
> prin
= do_QueryInterface(GetGlobalObject());
1448 nsJSContext::EvaluateString(const nsAString
& aScript
,
1450 nsIPrincipal
*aPrincipal
,
1454 nsAString
*aRetValue
,
1455 PRBool
* aIsUndefined
)
1457 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1458 __LINE__
, aURL
, aLineNo
);
1460 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1462 if (!mScriptsEnabled
) {
1464 *aIsUndefined
= PR_TRUE
;
1468 aRetValue
->Truncate();
1476 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1478 // Safety first: get an object representing the script's principals, i.e.,
1479 // the entities who signed this script, or the fully-qualified-domain-name
1480 // or "codebase" from which it was loaded.
1481 JSPrincipals
*jsprin
;
1482 nsIPrincipal
*principal
= aPrincipal
;
1484 aPrincipal
->GetJSPrincipals(mContext
, &jsprin
);
1487 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
1488 do_QueryInterface(GetGlobalObject(), &rv
);
1490 return NS_ERROR_FAILURE
;
1491 principal
= objPrincipal
->GetPrincipal();
1493 return NS_ERROR_FAILURE
;
1494 principal
->GetJSPrincipals(mContext
, &jsprin
);
1497 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1499 PRBool ok
= PR_FALSE
;
1501 rv
= sSecurityManager
->CanExecuteScripts(mContext
, principal
, &ok
);
1502 if (NS_FAILED(rv
)) {
1503 JSPRINCIPALS_DROP(mContext
, jsprin
);
1504 return NS_ERROR_FAILURE
;
1507 // Push our JSContext on the current thread's context stack so JS called
1508 // from native code via XPConnect uses the right context. Do this whether
1509 // or not the SecurityManager said "ok", in order to simplify control flow
1510 // below where we pop before returning.
1511 nsCOMPtr
<nsIJSContextStack
> stack
=
1512 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1513 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1514 JSPRINCIPALS_DROP(mContext
, jsprin
);
1515 return NS_ERROR_FAILURE
;
1518 // The result of evaluation, used only if there were no errors. This need
1519 // not be a GC root currently, provided we run the GC only from the
1520 // operation callback or from ScriptEvaluated.
1521 jsval val
= JSVAL_VOID
;
1522 jsval
* vp
= aRetValue
? &val
: NULL
;
1524 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1525 NS_ENSURE_SUCCESS(rv
, rv
);
1527 nsJSContext::TerminationFuncHolder
holder(this);
1531 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1532 // Since the caller is responsible for parsing the version strings, we just
1533 // check it isn't JSVERSION_UNKNOWN.
1534 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1535 JSAutoRequest
ar(mContext
);
1536 JSAutoEnterCompartment ac
;
1537 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1539 JSPRINCIPALS_DROP(mContext
, jsprin
);
1540 return NS_ERROR_FAILURE
;
1543 ok
= ::JS_EvaluateUCScriptForPrincipalsVersion(mContext
,
1544 (JSObject
*)aScopeObject
,
1546 (jschar
*)PromiseFlatString(aScript
).get(),
1551 JSVersion(aVersion
));
1554 // Tell XPConnect about any pending exceptions. This is needed
1555 // to avoid dropping JS exceptions in case we got here through
1556 // nested calls through XPConnect.
1558 ReportPendingException();
1562 // Whew! Finally done with these manually ref-counted things.
1563 JSPRINCIPALS_DROP(mContext
, jsprin
);
1565 // If all went well, convert val to a string if one is wanted.
1567 JSAutoRequest
ar(mContext
);
1568 JSAutoEnterCompartment ac
;
1569 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1572 rv
= JSValueToAString(mContext
, val
, aRetValue
, aIsUndefined
);
1576 *aIsUndefined
= PR_TRUE
;
1580 aRetValue
->Truncate();
1586 sSecurityManager
->PopContextPrincipal(mContext
);
1588 // Pop here, after JS_ValueToString and any other possible evaluation.
1589 if (NS_FAILED(stack
->Pop(nsnull
)))
1590 rv
= NS_ERROR_FAILURE
;
1592 // ScriptEvaluated needs to come after we pop the stack
1593 ScriptEvaluated(PR_TRUE
);
1599 nsJSContext::CompileScript(const PRUnichar
* aText
,
1600 PRInt32 aTextLength
,
1602 nsIPrincipal
*aPrincipal
,
1606 nsScriptObjectHolder
&aScriptObject
)
1608 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1611 NS_ENSURE_ARG_POINTER(aPrincipal
);
1614 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1616 JSPrincipals
*jsprin
;
1617 aPrincipal
->GetJSPrincipals(mContext
, &jsprin
);
1618 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1620 PRBool ok
= PR_FALSE
;
1622 rv
= sSecurityManager
->CanExecuteScripts(mContext
, aPrincipal
, &ok
);
1623 if (NS_FAILED(rv
)) {
1624 JSPRINCIPALS_DROP(mContext
, jsprin
);
1625 return NS_ERROR_FAILURE
;
1628 aScriptObject
.drop(); // ensure old object not used on failure...
1630 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1631 // Since the caller is responsible for parsing the version strings, we just
1632 // check it isn't JSVERSION_UNKNOWN.
1633 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1634 JSAutoRequest
ar(mContext
);
1637 ::JS_CompileUCScriptForPrincipalsVersion(mContext
,
1638 (JSObject
*)aScopeObject
,
1644 JSVersion(aVersion
));
1646 JSObject
*scriptObject
= ::JS_NewScriptObject(mContext
, script
);
1648 NS_ASSERTION(aScriptObject
.getScriptTypeID()==JAVASCRIPT
,
1649 "Expecting JS script object holder");
1650 rv
= aScriptObject
.set(scriptObject
);
1652 ::JS_DestroyScript(mContext
, script
);
1656 rv
= NS_ERROR_OUT_OF_MEMORY
;
1660 // Whew! Finally done.
1661 JSPRINCIPALS_DROP(mContext
, jsprin
);
1666 nsJSContext::ExecuteScript(void *aScriptObject
,
1668 nsAString
* aRetValue
,
1669 PRBool
* aIsUndefined
)
1671 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1673 if (!mScriptsEnabled
) {
1675 *aIsUndefined
= PR_TRUE
;
1679 aRetValue
->Truncate();
1688 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1690 // Push our JSContext on our thread's context stack, in case native code
1691 // called from JS calls back into JS via XPConnect.
1692 nsCOMPtr
<nsIJSContextStack
> stack
=
1693 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1694 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1695 return NS_ERROR_FAILURE
;
1698 // The result of evaluation, used only if there were no errors. This need
1699 // not be a GC root currently, provided we run the GC only from the
1700 // operation callback or from ScriptEvaluated.
1704 JSObject
*scriptObj
= (JSObject
*)aScriptObject
;
1705 nsCOMPtr
<nsIPrincipal
> principal
;
1707 rv
= sSecurityManager
->GetObjectPrincipal(mContext
, scriptObj
, getter_AddRefs(principal
));
1708 NS_ENSURE_SUCCESS(rv
, rv
);
1710 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1711 NS_ENSURE_SUCCESS(rv
, rv
);
1713 nsJSContext::TerminationFuncHolder
holder(this);
1714 JSAutoRequest
ar(mContext
);
1716 ok
= ::JS_ExecuteScript(mContext
,
1717 (JSObject
*)aScopeObject
,
1718 (JSScript
*)::JS_GetPrivate(mContext
, scriptObj
),
1722 // If all went well, convert val to a string (XXXbe unless undefined?).
1723 rv
= JSValueToAString(mContext
, val
, aRetValue
, aIsUndefined
);
1726 *aIsUndefined
= PR_TRUE
;
1730 aRetValue
->Truncate();
1736 sSecurityManager
->PopContextPrincipal(mContext
);
1738 // Pop here, after JS_ValueToString and any other possible evaluation.
1739 if (NS_FAILED(stack
->Pop(nsnull
)))
1740 rv
= NS_ERROR_FAILURE
;
1742 // ScriptEvaluated needs to come after we pop the stack
1743 ScriptEvaluated(PR_TRUE
);
1751 AtomIsEventHandlerName(nsIAtom
*aName
)
1753 const PRUnichar
*name
= aName
->GetUTF16String();
1755 const PRUnichar
*cp
;
1757 for (cp
= name
; *cp
!= '\0'; ++cp
)
1760 if ((c
< 'A' || c
> 'Z') && (c
< 'a' || c
> 'z'))
1768 // Helper function to find the JSObject associated with a (presumably DOM)
1771 nsJSContext::JSObjectFromInterface(nsISupports
* aTarget
, void *aScope
, JSObject
**aRet
)
1773 // It is legal to specify a null target.
1779 // Get the jsobject associated with this target
1780 // We don't wrap here because we trust the JS engine to wrap the target
1784 rv
= nsContentUtils::WrapNative(mContext
, (JSObject
*)aScope
, aTarget
, &v
);
1785 NS_ENSURE_SUCCESS(rv
, rv
);
1788 nsCOMPtr
<nsISupports
> targetSupp
= do_QueryInterface(aTarget
);
1789 nsCOMPtr
<nsISupports
> native
=
1790 nsContentUtils::XPConnect()->GetNativeOfWrapper(mContext
,
1791 JSVAL_TO_OBJECT(v
));
1792 NS_ASSERTION(native
== targetSupp
, "Native should be the target!");
1795 *aRet
= JSVAL_TO_OBJECT(v
);
1802 nsJSContext::CompileEventHandler(nsIAtom
*aName
,
1804 const char** aArgNames
,
1805 const nsAString
& aBody
,
1806 const char *aURL
, PRUint32 aLineNo
,
1808 nsScriptObjectHolder
&aHandler
)
1810 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1811 __LINE__
, aURL
, aLineNo
);
1813 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1815 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
1816 NS_PRECONDITION(!::JS_IsExceptionPending(mContext
),
1817 "Why are we being called with a pending exception?");
1819 if (!sSecurityManager
) {
1820 NS_ERROR("Huh, we need a script security manager to compile "
1821 "an event handler!");
1823 return NS_ERROR_UNEXPECTED
;
1826 // Don't compile if aVersion is unknown. Since the caller is responsible for
1827 // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
1828 if ((JSVersion
)aVersion
== JSVERSION_UNKNOWN
) {
1829 return NS_ERROR_ILLEGAL_VALUE
;
1833 JSContext
* top
= nsContentUtils::GetCurrentJSContext();
1834 NS_ASSERTION(mContext
== top
, "Context not properly pushed!");
1837 // Event handlers are always shared, and must be bound before use.
1838 // Therefore we never bother compiling with principals.
1839 // (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
1840 JSAutoRequest
ar(mContext
);
1843 ::JS_CompileUCFunctionForPrincipalsVersion(mContext
,
1845 nsAtomCString(aName
).get(), aArgCount
, aArgNames
,
1846 (jschar
*)PromiseFlatString(aBody
).get(),
1848 aURL
, aLineNo
, JSVersion(aVersion
));
1851 ReportPendingException();
1852 return NS_ERROR_ILLEGAL_VALUE
;
1855 JSObject
*handler
= ::JS_GetFunctionObject(fun
);
1856 NS_ASSERTION(aHandler
.getScriptTypeID()==JAVASCRIPT
,
1857 "Expecting JS script object holder");
1858 return aHandler
.set((void *)handler
);
1861 // XXX - note that CompileFunction doesn't yet play the nsScriptObjectHolder
1862 // game - caller must still ensure JS GC root.
1864 nsJSContext::CompileFunction(void* aTarget
,
1865 const nsACString
& aName
,
1867 const char** aArgArray
,
1868 const nsAString
& aBody
,
1873 void** aFunctionObject
)
1875 NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s, url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1876 __LINE__
, aName
.BeginReading(), aURL
, aLineNo
);
1878 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1880 // Don't compile if aVersion is unknown. Since the caller is responsible for
1881 // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
1882 if ((JSVersion
)aVersion
== JSVERSION_UNKNOWN
) {
1883 return NS_ERROR_ILLEGAL_VALUE
;
1886 JSPrincipals
*jsprin
= nsnull
;
1888 nsIScriptGlobalObject
*global
= GetGlobalObject();
1890 // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
1891 nsCOMPtr
<nsIScriptObjectPrincipal
> globalData
= do_QueryInterface(global
);
1893 nsIPrincipal
*prin
= globalData
->GetPrincipal();
1895 return NS_ERROR_FAILURE
;
1896 prin
->GetJSPrincipals(mContext
, &jsprin
);
1900 JSObject
*target
= (JSObject
*)aTarget
;
1902 JSAutoRequest
ar(mContext
);
1905 ::JS_CompileUCFunctionForPrincipalsVersion(mContext
,
1906 aShared
? nsnull
: target
, jsprin
,
1907 PromiseFlatCString(aName
).get(),
1908 aArgCount
, aArgArray
,
1909 (jschar
*)PromiseFlatString(aBody
).get(),
1912 JSVersion(aVersion
));
1915 JSPRINCIPALS_DROP(mContext
, jsprin
);
1917 return NS_ERROR_FAILURE
;
1919 JSObject
*handler
= ::JS_GetFunctionObject(fun
);
1920 if (aFunctionObject
)
1921 *aFunctionObject
= (void*) handler
;
1926 nsJSContext::CallEventHandler(nsISupports
* aTarget
, void *aScope
, void *aHandler
,
1927 nsIArray
*aargv
, nsIVariant
**arv
)
1929 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1931 if (!mScriptsEnabled
) {
1935 #ifdef NS_FUNCTION_TIMER
1937 JSObject
*obj
= static_cast<JSObject
*>(aHandler
);
1938 JSString
*id
= JS_GetFunctionId(static_cast<JSFunction
*>(JS_GetPrivate(mContext
, obj
)));
1939 JSAutoByteString bytes
;
1940 const char *name
= !id
? "anonymous" : bytes
.encode(mContext
, id
) ? bytes
.ptr() : "<error>";
1941 NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME
, __LINE__
, name
);
1945 JSAutoRequest
ar(mContext
);
1946 JSObject
* target
= nsnull
;
1947 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &target
);
1948 NS_ENSURE_SUCCESS(rv
, rv
);
1950 js::AutoObjectRooter
targetVal(mContext
, target
);
1951 jsval rval
= JSVAL_VOID
;
1953 // This one's a lot easier than EvaluateString because we don't have to
1954 // hassle with principals: they're already compiled into the JS function.
1955 // xxxmarkh - this comment is no longer true - principals are not used at
1956 // all now, and never were in some cases.
1959 if (!pusher
.Push(mContext
, PR_TRUE
))
1960 return NS_ERROR_FAILURE
;
1962 // check if the event handler can be run on the object in question
1963 rv
= sSecurityManager
->CheckFunctionAccess(mContext
, aHandler
, target
);
1965 nsJSContext::TerminationFuncHolder
holder(this);
1967 if (NS_SUCCEEDED(rv
)) {
1968 // Convert args to jsvals.
1970 jsval
*argv
= nsnull
;
1972 js::LazilyConstructed
<nsAutoPoolRelease
> poolRelease
;
1973 js::LazilyConstructed
<js::AutoArrayRooter
> tvr
;
1975 // Use |target| as the scope for wrapping the arguments, since aScope is
1976 // the safe scope in many cases, which isn't very useful. Wrapping aTarget
1977 // was OK because those typically have PreCreate methods that give them the
1978 // right scope anyway, and we want to make sure that the arguments end up
1979 // in the same scope as aTarget.
1980 rv
= ConvertSupportsTojsvals(aargv
, target
, &argc
,
1981 &argv
, poolRelease
, tvr
);
1982 NS_ENSURE_SUCCESS(rv
, rv
);
1984 JSObject
*funobj
= static_cast<JSObject
*>(aHandler
);
1985 nsCOMPtr
<nsIPrincipal
> principal
;
1986 rv
= sSecurityManager
->GetObjectPrincipal(mContext
, funobj
,
1987 getter_AddRefs(principal
));
1988 NS_ENSURE_SUCCESS(rv
, rv
);
1990 JSStackFrame
*currentfp
= nsnull
;
1991 rv
= sSecurityManager
->PushContextPrincipal(mContext
,
1992 JS_FrameIterator(mContext
, ¤tfp
),
1994 NS_ENSURE_SUCCESS(rv
, rv
);
1996 jsval funval
= OBJECT_TO_JSVAL(funobj
);
1997 JSAutoEnterCompartment ac
;
1998 if (!ac
.enter(mContext
, target
)) {
1999 sSecurityManager
->PopContextPrincipal(mContext
);
2000 return NS_ERROR_FAILURE
;
2004 PRBool ok
= ::JS_CallFunctionValue(mContext
, target
,
2005 funval
, argc
, argv
, &rval
);
2009 // Tell XPConnect about any pending exceptions. This is needed
2010 // to avoid dropping JS exceptions in case we got here through
2011 // nested calls through XPConnect.
2013 ReportPendingException();
2015 // Don't pass back results from failed calls.
2018 // Tell the caller that the handler threw an error.
2019 rv
= NS_ERROR_FAILURE
;
2022 sSecurityManager
->PopContextPrincipal(mContext
);
2027 // Convert to variant before calling ScriptEvaluated, as it may GC, meaning
2028 // we would need to root rval.
2029 if (NS_SUCCEEDED(rv
)) {
2030 if (rval
== JSVAL_NULL
)
2033 rv
= nsContentUtils::XPConnect()->JSToVariant(mContext
, rval
, arv
);
2036 // ScriptEvaluated needs to come after we pop the stack
2037 ScriptEvaluated(PR_TRUE
);
2043 nsJSContext::BindCompiledEventHandler(nsISupports
* aTarget
, void *aScope
,
2047 NS_ENSURE_ARG(aHandler
);
2048 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
2050 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
2052 JSAutoRequest
ar(mContext
);
2054 // Get the jsobject associated with this target
2055 JSObject
*target
= nsnull
;
2056 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &target
);
2057 NS_ENSURE_SUCCESS(rv
, rv
);
2059 JSObject
*funobj
= (JSObject
*) aHandler
;
2063 JSAutoEnterCompartment ac
;
2064 if (!ac
.enter(mContext
, funobj
)) {
2065 return NS_ERROR_FAILURE
;
2068 NS_ASSERTION(JS_TypeOfValue(mContext
,
2069 OBJECT_TO_JSVAL(funobj
)) == JSTYPE_FUNCTION
,
2070 "Event handler object not a function");
2074 JSAutoEnterCompartment ac
;
2075 if (!ac
.enter(mContext
, target
)) {
2076 return NS_ERROR_FAILURE
;
2079 // Push our JSContext on our thread's context stack, in case native code
2080 // called from JS calls back into JS via XPConnect.
2081 nsCOMPtr
<nsIJSContextStack
> stack
=
2082 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
2083 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
2084 return NS_ERROR_FAILURE
;
2087 // Make sure the handler function is parented by its event target object
2088 if (funobj
) { // && ::JS_GetParent(mContext, funobj) != target) {
2089 funobj
= ::JS_CloneFunctionObject(mContext
, funobj
, target
);
2091 rv
= NS_ERROR_OUT_OF_MEMORY
;
2094 if (NS_SUCCEEDED(rv
) &&
2095 // Make sure the flags here match those in nsEventReceiverSH::NewResolve
2096 !::JS_DefineProperty(mContext
, target
, nsAtomCString(aName
).get(),
2097 OBJECT_TO_JSVAL(funobj
), nsnull
, nsnull
,
2098 JSPROP_ENUMERATE
| JSPROP_PERMANENT
)) {
2099 ReportPendingException();
2100 rv
= NS_ERROR_FAILURE
;
2103 // XXXmarkh - ideally we should assert that the wrapped native is now
2104 // "long lived" - how to do that?
2106 if (NS_FAILED(stack
->Pop(nsnull
)) && NS_SUCCEEDED(rv
)) {
2107 rv
= NS_ERROR_FAILURE
;
2114 nsJSContext::GetBoundEventHandler(nsISupports
* aTarget
, void *aScope
,
2116 nsScriptObjectHolder
&aHandler
)
2118 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
2120 JSAutoRequest
ar(mContext
);
2121 JSObject
*obj
= nsnull
;
2122 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &obj
);
2123 NS_ENSURE_SUCCESS(rv
, rv
);
2125 JSAutoEnterCompartment ac
;
2126 if (!ac
.enter(mContext
, obj
)) {
2127 return NS_ERROR_FAILURE
;
2131 if (!JS_LookupProperty(mContext
, obj
,
2132 nsAtomCString(aName
).get(), &funval
))
2133 return NS_ERROR_FAILURE
;
2135 if (JS_TypeOfValue(mContext
, funval
) != JSTYPE_FUNCTION
) {
2136 NS_WARNING("Event handler object not a function");
2140 NS_ASSERTION(aHandler
.getScriptTypeID()==JAVASCRIPT
,
2141 "Expecting JS script object holder");
2142 return aHandler
.set(JSVAL_TO_OBJECT(funval
));
2147 nsJSContext::Serialize(nsIObjectOutputStream
* aStream
, void *aScriptObject
)
2149 JSObject
*mJSObject
= (JSObject
*)aScriptObject
;
2151 return NS_ERROR_FAILURE
;
2155 JSContext
* cx
= mContext
;
2156 JSXDRState
*xdr
= ::JS_XDRNewMem(cx
, JSXDR_ENCODE
);
2158 return NS_ERROR_OUT_OF_MEMORY
;
2159 xdr
->userdata
= (void*) aStream
;
2161 JSAutoRequest
ar(cx
);
2162 JSScript
*script
= reinterpret_cast<JSScript
*>
2163 (::JS_GetPrivate(cx
, mJSObject
));
2164 if (! ::JS_XDRScript(xdr
, &script
)) {
2165 rv
= NS_ERROR_FAILURE
; // likely to be a principals serialization error
2167 // Get the encoded JSXDRState data and write it. The JSXDRState owns
2168 // this buffer memory and will free it beneath ::JS_XDRDestroy.
2170 // If an XPCOM object needs to be written in the midst of the JS XDR
2171 // encoding process, the C++ code called back from the JS engine (e.g.,
2172 // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data
2173 // from the JSXDRState to aStream, then write the object, then return
2174 // to JS XDR code with xdr reset so new JS data is encoded at the front
2175 // of the xdr's data buffer.
2177 // However many XPCOM objects are interleaved with JS XDR data in the
2178 // stream, when control returns here from ::JS_XDRScript, we'll have
2179 // one last buffer of data to write to aStream.
2182 const char* data
= reinterpret_cast<const char*>
2183 (::JS_XDRMemGetData(xdr
, &size
));
2184 NS_ASSERTION(data
, "no decoded JSXDRState data!");
2186 rv
= aStream
->Write32(size
);
2187 if (NS_SUCCEEDED(rv
))
2188 rv
= aStream
->WriteBytes(data
, size
);
2191 ::JS_XDRDestroy(xdr
);
2192 if (NS_FAILED(rv
)) return rv
;
2198 nsJSContext::Deserialize(nsIObjectInputStream
* aStream
,
2199 nsScriptObjectHolder
&aResult
)
2201 JSObject
*result
= nsnull
;
2204 NS_TIME_FUNCTION_MIN(1.0);
2206 NS_TIMELINE_MARK_FUNCTION("js script deserialize");
2209 rv
= aStream
->Read32(&size
);
2210 if (NS_FAILED(rv
)) return rv
;
2213 rv
= aStream
->ReadBytes(size
, &data
);
2214 if (NS_FAILED(rv
)) return rv
;
2216 JSContext
* cx
= mContext
;
2218 JSXDRState
*xdr
= ::JS_XDRNewMem(cx
, JSXDR_DECODE
);
2220 rv
= NS_ERROR_OUT_OF_MEMORY
;
2222 xdr
->userdata
= (void*) aStream
;
2223 JSAutoRequest
ar(cx
);
2224 ::JS_XDRMemSetData(xdr
, data
, size
);
2226 JSScript
*script
= nsnull
;
2227 if (! ::JS_XDRScript(xdr
, &script
)) {
2228 rv
= NS_ERROR_FAILURE
; // principals deserialization error?
2230 result
= ::JS_NewScriptObject(cx
, script
);
2232 rv
= NS_ERROR_OUT_OF_MEMORY
; // certain error
2233 ::JS_DestroyScript(cx
, script
);
2237 // Update data in case ::JS_XDRScript called back into C++ code to
2238 // read an XPCOM object.
2240 // In that case, the serialization process must have flushed a run
2241 // of counted bytes containing JS data at the point where the XPCOM
2242 // object starts, after which an encoding C++ callback from the JS
2243 // XDR code must have written the XPCOM object directly into the
2244 // nsIObjectOutputStream.
2246 // The deserialization process will XDR-decode counted bytes up to
2247 // but not including the XPCOM object, then call back into C++ to
2248 // read the object, then read more counted bytes and hand them off
2249 // to the JSXDRState, so more JS data can be decoded.
2251 // This interleaving of JS XDR data and XPCOM object data may occur
2252 // several times beneath the call to ::JS_XDRScript, above. At the
2253 // end of the day, we need to free (via nsMemory) the data owned by
2254 // the JSXDRState. So we steal it back, nulling xdr's buffer so it
2255 // doesn't get passed to ::JS_free by ::JS_XDRDestroy.
2258 data
= (char*) ::JS_XDRMemGetData(xdr
, &junk
);
2260 ::JS_XDRMemSetData(xdr
, NULL
, 0);
2261 ::JS_XDRDestroy(xdr
);
2264 // If data is null now, it must have been freed while deserializing an
2265 // XPCOM object (e.g., a principal) beneath ::JS_XDRScript.
2267 nsMemory::Free(data
);
2268 NS_ASSERTION(aResult
.getScriptTypeID()==JAVASCRIPT
,
2269 "Expecting JS script object holder");
2271 // Now that we've cleaned up, handle the case when rv is a failure
2272 // code, which could happen for all sorts of reasons above.
2273 NS_ENSURE_SUCCESS(rv
, rv
);
2275 return aResult
.set(result
);
2279 nsJSContext::SetDefaultLanguageVersion(PRUint32 aVersion
)
2281 ::JS_SetVersion(mContext
, (JSVersion
)aVersion
);
2284 nsIScriptGlobalObject
*
2285 nsJSContext::GetGlobalObject()
2287 JSObject
*global
= ::JS_GetGlobalObject(mContext
);
2293 OBJ_TO_INNER_OBJECT(mContext
, global
);
2298 JSClass
*c
= JS_GET_CLASS(mContext
, global
);
2300 if (!c
|| ((~c
->flags
) & (JSCLASS_HAS_PRIVATE
|
2301 JSCLASS_PRIVATE_IS_NSISUPPORTS
))) {
2305 JSAutoEnterCompartment ac
;
2307 // NB: This AutoCrossCompartmentCall is only here to silence a warning. If
2308 // it fails, nothing bad will happen.
2309 ac
.enterAndIgnoreErrors(mContext
, global
);
2311 nsCOMPtr
<nsIScriptGlobalObject
> sgo
;
2313 (nsISupports
*)::JS_GetPrivate(mContext
, global
);
2315 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapped_native
=
2316 do_QueryInterface(priv
);
2318 if (wrapped_native
) {
2319 // The global object is a XPConnect wrapped native, the native in
2320 // the wrapper might be the nsIScriptGlobalObject
2322 sgo
= do_QueryWrappedNative(wrapped_native
);
2324 sgo
= do_QueryInterface(priv
);
2327 // This'll return a pointer to something we're about to release, but
2328 // that's ok, the JS object will hold it alive long enough.
2329 nsCOMPtr
<nsPIDOMWindow
> pwin(do_QueryInterface(sgo
));
2333 return static_cast<nsGlobalWindow
*>(pwin
->GetOuterWindow());
2337 nsJSContext::GetNativeGlobal()
2339 return ::JS_GetGlobalObject(mContext
);
2343 nsJSContext::CreateNativeGlobalForInner(
2344 nsIScriptGlobalObject
*aNewInner
,
2346 nsIPrincipal
*aPrincipal
,
2347 void **aNativeGlobal
, nsISupports
**aHolder
)
2349 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2350 PRUint32 flags
= aIsChrome
? nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT
: 0;
2351 nsCOMPtr
<nsIXPConnectJSObjectHolder
> jsholder
;
2353 nsCOMPtr
<nsIPrincipal
> systemPrincipal
;
2355 nsIScriptSecurityManager
*ssm
= nsContentUtils::GetSecurityManager();
2356 ssm
->GetSystemPrincipal(getter_AddRefs(systemPrincipal
));
2360 InitClassesWithNewWrappedGlobal(mContext
,
2361 aNewInner
, NS_GET_IID(nsISupports
),
2362 aIsChrome
? systemPrincipal
.get() : aPrincipal
,
2364 getter_AddRefs(jsholder
));
2367 jsholder
->GetJSObject(reinterpret_cast<JSObject
**>(aNativeGlobal
));
2368 *aHolder
= jsholder
.get();
2369 NS_ADDREF(*aHolder
);
2374 nsJSContext::ConnectToInner(nsIScriptGlobalObject
*aNewInner
, void *aOuterGlobal
)
2376 NS_ENSURE_ARG(aNewInner
);
2377 JSObject
*newInnerJSObject
= (JSObject
*)aNewInner
->GetScriptGlobal(JAVASCRIPT
);
2378 JSObject
*outerGlobal
= (JSObject
*)aOuterGlobal
;
2380 // Now that we're connecting the outer global to the inner one,
2381 // we must have transplanted it. The JS engine tries to maintain
2382 // the global object's compartment as its default compartment,
2383 // so update that now since it might have changed.
2384 JS_SetGlobalObject(mContext
, outerGlobal
);
2385 NS_ASSERTION(JS_GetPrototype(mContext
, outerGlobal
) ==
2386 JS_GetPrototype(mContext
, newInnerJSObject
),
2387 "outer and inner globals should have the same prototype");
2393 nsJSContext::GetNativeContext()
2399 nsJSContext::InitContext()
2401 // Make sure callers of this use
2402 // WillInitializeContext/DidInitializeContext around this call.
2403 NS_ENSURE_TRUE(!mIsInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
2406 return NS_ERROR_OUT_OF_MEMORY
;
2408 ::JS_SetErrorReporter(mContext
, NS_ScriptErrorReporter
);
2414 nsJSContext::CreateOuterObject(nsIScriptGlobalObject
*aGlobalObject
,
2415 nsIScriptGlobalObject
*aCurrentInner
)
2417 mGlobalObjectRef
= aGlobalObject
;
2419 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(aGlobalObject
));
2423 // Flag this window's global object and objects under it as "system",
2424 // for optional automated XPCNativeWrapper construction when chrome JS
2425 // views a content DOM.
2426 flags
= nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT
;
2428 // Always enable E4X for XUL and other chrome content -- there is no
2429 // need to preserve the <!-- script hiding hack from JS-in-HTML daze
2430 // (introduced in 1995 for graceful script degradation in Netscape 1,
2431 // Mosaic, and other pre-JS browsers).
2432 JS_SetOptions(mContext
, JS_GetOptions(mContext
) | JSOPTION_XML
);
2436 NS_NewOuterWindowProxy(mContext
, aCurrentInner
->GetGlobalJSObject());
2438 return NS_ERROR_FAILURE
;
2441 return SetOuterObject(outer
);
2445 nsJSContext::SetOuterObject(void *aOuterObject
)
2447 JSObject
*outer
= static_cast<JSObject
*>(aOuterObject
);
2449 // Force our context's global object to be the outer.
2450 JS_SetGlobalObject(mContext
, outer
);
2452 // NB: JS_SetGlobalObject sets mContext->compartment.
2453 JSObject
*inner
= JS_GetParent(mContext
, outer
);
2455 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2456 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
2457 nsresult rv
= xpc
->GetWrappedNativeOfJSObject(mContext
, inner
,
2458 getter_AddRefs(wrapper
));
2459 NS_ENSURE_SUCCESS(rv
, rv
);
2460 NS_ABORT_IF_FALSE(wrapper
, "bad wrapper");
2462 wrapper
->RefreshPrototype();
2463 JS_SetPrototype(mContext
, outer
, JS_GetPrototype(mContext
, inner
));
2469 nsJSContext::InitOuterWindow()
2471 JSObject
*global
= JS_GetGlobalObject(mContext
);
2472 OBJ_TO_INNER_OBJECT(mContext
, global
);
2474 nsresult rv
= InitClasses(global
); // this will complete global object initialization
2475 NS_ENSURE_SUCCESS(rv
, rv
);
2481 nsJSContext::InitializeExternalClasses()
2483 nsScriptNameSpaceManager
*nameSpaceManager
= nsJSRuntime::GetNameSpaceManager();
2484 NS_ENSURE_TRUE(nameSpaceManager
, NS_ERROR_NOT_INITIALIZED
);
2486 return nameSpaceManager
->InitForContext(this);
2490 nsJSContext::SetProperty(void *aTarget
, const char *aPropName
, nsISupports
*aArgs
)
2493 jsval
*argv
= nsnull
;
2495 JSAutoRequest
ar(mContext
);
2497 js::LazilyConstructed
<nsAutoPoolRelease
> poolRelease
;
2498 js::LazilyConstructed
<js::AutoArrayRooter
> tvr
;
2501 rv
= ConvertSupportsTojsvals(aArgs
, GetNativeGlobal(), &argc
,
2502 &argv
, poolRelease
, tvr
);
2503 NS_ENSURE_SUCCESS(rv
, rv
);
2507 // got the arguments, now attach them.
2509 // window.dialogArguments is supposed to be an array if a JS array
2510 // was passed to showModalDialog(), deal with that here.
2511 if (strcmp(aPropName
, "dialogArguments") == 0 && argc
<= 1) {
2512 vargs
= argc
? argv
[0] : JSVAL_VOID
;
2514 for (PRUint32 i
= 0; i
< argc
; ++i
) {
2515 if (!JS_WrapValue(mContext
, &argv
[i
])) {
2516 return NS_ERROR_FAILURE
;
2520 JSObject
*args
= ::JS_NewArrayObject(mContext
, argc
, argv
);
2521 vargs
= OBJECT_TO_JSVAL(args
);
2524 // Make sure to use JS_DefineProperty here so that we can override
2525 // readonly XPConnect properties here as well (read dialogArguments).
2526 rv
= ::JS_DefineProperty(mContext
, reinterpret_cast<JSObject
*>(aTarget
),
2527 aPropName
, vargs
, nsnull
, nsnull
, 0) ?
2528 NS_OK
: NS_ERROR_FAILURE
;
2534 nsJSContext::ConvertSupportsTojsvals(nsISupports
*aArgs
,
2538 js::LazilyConstructed
<nsAutoPoolRelease
> &aPoolRelease
,
2539 js::LazilyConstructed
<js::AutoArrayRooter
> &aRooter
)
2541 nsresult rv
= NS_OK
;
2543 // If the array implements nsIJSArgArray, just grab the values directly.
2544 nsCOMPtr
<nsIJSArgArray
> fastArray
= do_QueryInterface(aArgs
);
2545 if (fastArray
!= nsnull
)
2546 return fastArray
->GetArgs(aArgc
, reinterpret_cast<void **>(aArgv
));
2548 // Take the slower path converting each item.
2549 // Handle only nsIArray and nsIVariant. nsIArray is only needed for
2550 // SetProperty('arguments', ...);
2555 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2556 NS_ENSURE_TRUE(xpc
, NS_ERROR_UNEXPECTED
);
2560 PRUint32 argCtr
, argCount
;
2561 // This general purpose function may need to convert an arg array
2562 // (window.arguments, event-handler args) and a generic property.
2563 nsCOMPtr
<nsIArray
> argsArray(do_QueryInterface(aArgs
));
2566 rv
= argsArray
->GetLength(&argCount
);
2567 NS_ENSURE_SUCCESS(rv
, rv
);
2571 argCount
= 1; // the nsISupports which is not an array
2574 void *mark
= JS_ARENA_MARK(&mContext
->tempPool
);
2576 size_t nbytes
= argCount
* sizeof(jsval
);
2577 JS_ARENA_ALLOCATE_CAST(argv
, jsval
*, &mContext
->tempPool
, nbytes
);
2578 NS_ENSURE_TRUE(argv
, NS_ERROR_OUT_OF_MEMORY
);
2579 memset(argv
, 0, nbytes
); /* initialize so GC-able */
2581 // Use the caller's auto guards to release and unroot.
2582 aPoolRelease
.construct(&mContext
->tempPool
, mark
);
2583 aRooter
.construct(mContext
, argCount
, argv
);
2586 for (argCtr
= 0; argCtr
< argCount
&& NS_SUCCEEDED(rv
); argCtr
++) {
2587 nsCOMPtr
<nsISupports
> arg
;
2588 jsval
*thisval
= argv
+ argCtr
;
2589 argsArray
->QueryElementAt(argCtr
, NS_GET_IID(nsISupports
),
2590 getter_AddRefs(arg
));
2592 *thisval
= JSVAL_NULL
;
2595 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(arg
));
2596 if (variant
!= nsnull
) {
2597 rv
= xpc
->VariantToJS(mContext
, (JSObject
*)aScope
, variant
,
2600 // And finally, support the nsISupportsPrimitives supplied
2601 // by the AppShell. It generally will pass only strings, but
2602 // as we have code for handling all, we may as well use it.
2603 rv
= AddSupportsPrimitiveTojsvals(arg
, thisval
);
2604 if (rv
== NS_ERROR_NO_INTERFACE
) {
2605 // something else - probably an event object or similar -
2608 // but first, check its not another nsISupportsPrimitive, as
2609 // these are now deprecated for use with script contexts.
2610 nsCOMPtr
<nsISupportsPrimitive
> prim(do_QueryInterface(arg
));
2611 NS_ASSERTION(prim
== nsnull
,
2612 "Don't pass nsISupportsPrimitives - use nsIVariant!");
2614 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
2616 rv
= nsContentUtils::WrapNative(mContext
, (JSObject
*)aScope
, arg
,
2617 &v
, getter_AddRefs(wrapper
));
2618 if (NS_SUCCEEDED(rv
)) {
2625 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(aArgs
));
2627 rv
= xpc
->VariantToJS(mContext
, (JSObject
*)aScope
, variant
, argv
);
2629 NS_ERROR("Not an array, not an interface?");
2630 rv
= NS_ERROR_UNEXPECTED
;
2640 // This really should go into xpconnect somewhere...
2642 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports
*aArg
, jsval
*aArgv
)
2644 NS_PRECONDITION(aArg
, "Empty arg");
2646 nsCOMPtr
<nsISupportsPrimitive
> argPrimitive(do_QueryInterface(aArg
));
2648 return NS_ERROR_NO_INTERFACE
;
2650 JSContext
*cx
= mContext
;
2652 argPrimitive
->GetType(&type
);
2655 case nsISupportsPrimitive::TYPE_CSTRING
: {
2656 nsCOMPtr
<nsISupportsCString
> p(do_QueryInterface(argPrimitive
));
2657 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2664 JSString
*str
= ::JS_NewStringCopyN(cx
, data
.get(), data
.Length());
2665 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2667 *aArgv
= STRING_TO_JSVAL(str
);
2671 case nsISupportsPrimitive::TYPE_STRING
: {
2672 nsCOMPtr
<nsISupportsString
> p(do_QueryInterface(argPrimitive
));
2673 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2679 // cast is probably safe since wchar_t and jschar are expected
2680 // to be equivalent; both unsigned 16-bit entities
2682 ::JS_NewUCStringCopyN(cx
,
2683 reinterpret_cast<const jschar
*>(data
.get()),
2685 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2687 *aArgv
= STRING_TO_JSVAL(str
);
2690 case nsISupportsPrimitive::TYPE_PRBOOL
: {
2691 nsCOMPtr
<nsISupportsPRBool
> p(do_QueryInterface(argPrimitive
));
2692 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2698 *aArgv
= BOOLEAN_TO_JSVAL(data
);
2702 case nsISupportsPrimitive::TYPE_PRUINT8
: {
2703 nsCOMPtr
<nsISupportsPRUint8
> p(do_QueryInterface(argPrimitive
));
2704 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2710 *aArgv
= INT_TO_JSVAL(data
);
2714 case nsISupportsPrimitive::TYPE_PRUINT16
: {
2715 nsCOMPtr
<nsISupportsPRUint16
> p(do_QueryInterface(argPrimitive
));
2716 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2722 *aArgv
= INT_TO_JSVAL(data
);
2726 case nsISupportsPrimitive::TYPE_PRUINT32
: {
2727 nsCOMPtr
<nsISupportsPRUint32
> p(do_QueryInterface(argPrimitive
));
2728 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2734 *aArgv
= INT_TO_JSVAL(data
);
2738 case nsISupportsPrimitive::TYPE_CHAR
: {
2739 nsCOMPtr
<nsISupportsChar
> p(do_QueryInterface(argPrimitive
));
2740 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2746 JSString
*str
= ::JS_NewStringCopyN(cx
, &data
, 1);
2747 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2749 *aArgv
= STRING_TO_JSVAL(str
);
2753 case nsISupportsPrimitive::TYPE_PRINT16
: {
2754 nsCOMPtr
<nsISupportsPRInt16
> p(do_QueryInterface(argPrimitive
));
2755 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2761 *aArgv
= INT_TO_JSVAL(data
);
2765 case nsISupportsPrimitive::TYPE_PRINT32
: {
2766 nsCOMPtr
<nsISupportsPRInt32
> p(do_QueryInterface(argPrimitive
));
2767 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2773 *aArgv
= INT_TO_JSVAL(data
);
2777 case nsISupportsPrimitive::TYPE_FLOAT
: {
2778 nsCOMPtr
<nsISupportsFloat
> p(do_QueryInterface(argPrimitive
));
2779 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2785 JSBool ok
= ::JS_NewNumberValue(cx
, data
, aArgv
);
2786 NS_ENSURE_TRUE(ok
, NS_ERROR_OUT_OF_MEMORY
);
2790 case nsISupportsPrimitive::TYPE_DOUBLE
: {
2791 nsCOMPtr
<nsISupportsDouble
> p(do_QueryInterface(argPrimitive
));
2792 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2798 JSBool ok
= ::JS_NewNumberValue(cx
, data
, aArgv
);
2799 NS_ENSURE_TRUE(ok
, NS_ERROR_OUT_OF_MEMORY
);
2803 case nsISupportsPrimitive::TYPE_INTERFACE_POINTER
: {
2804 nsCOMPtr
<nsISupportsInterfacePointer
> p(do_QueryInterface(argPrimitive
));
2805 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2807 nsCOMPtr
<nsISupports
> data
;
2808 nsIID
*iid
= nsnull
;
2810 p
->GetData(getter_AddRefs(data
));
2811 p
->GetDataIID(&iid
);
2812 NS_ENSURE_TRUE(iid
, NS_ERROR_UNEXPECTED
);
2814 AutoFree
iidGuard(iid
); // Free iid upon destruction.
2816 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
2818 nsresult rv
= nsContentUtils::WrapNative(cx
, ::JS_GetGlobalObject(cx
),
2820 getter_AddRefs(wrapper
));
2821 NS_ENSURE_SUCCESS(rv
, rv
);
2827 case nsISupportsPrimitive::TYPE_ID
:
2828 case nsISupportsPrimitive::TYPE_PRUINT64
:
2829 case nsISupportsPrimitive::TYPE_PRINT64
:
2830 case nsISupportsPrimitive::TYPE_PRTIME
:
2831 case nsISupportsPrimitive::TYPE_VOID
: {
2832 NS_WARNING("Unsupported primitive type used");
2833 *aArgv
= JSVAL_NULL
;
2837 NS_WARNING("Unknown primitive type used");
2838 *aArgv
= JSVAL_NULL
;
2845 static JSPropertySpec OptionsProperties
[] = {
2846 {"strict", (int8
)JSOPTION_STRICT
, JSPROP_ENUMERATE
| JSPROP_PERMANENT
},
2847 {"werror", (int8
)JSOPTION_WERROR
, JSPROP_ENUMERATE
| JSPROP_PERMANENT
},
2848 {"relimit", (int8
)JSOPTION_RELIMIT
, JSPROP_ENUMERATE
| JSPROP_PERMANENT
},
2853 GetOptionsProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
2855 if (JSID_IS_INT(id
)) {
2856 uint32 optbit
= (uint32
) JSID_TO_INT(id
);
2857 if (((optbit
& (optbit
- 1)) == 0 && optbit
<= JSOPTION_WERROR
) ||
2858 optbit
== JSOPTION_RELIMIT
)
2859 *vp
= (JS_GetOptions(cx
) & optbit
) ? JSVAL_TRUE
: JSVAL_FALSE
;
2865 SetOptionsProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
2867 if (JSID_IS_INT(id
)) {
2868 uint32 optbit
= (uint32
) JSID_TO_INT(id
);
2870 // Don't let options other than strict, werror, or relimit be set -- it
2871 // would be bad if web page script could clear
2872 // JSOPTION_PRIVATE_IS_NSISUPPORTS!
2873 if (((optbit
& (optbit
- 1)) == 0 && optbit
<= JSOPTION_WERROR
) ||
2874 optbit
== JSOPTION_RELIMIT
) {
2876 JS_ValueToBoolean(cx
, *vp
, &optval
);
2878 uint32 optset
= ::JS_GetOptions(cx
);
2883 ::JS_SetOptions(cx
, optset
);
2889 static JSClass OptionsClass
= {
2892 JS_PropertyStub
, JS_PropertyStub
, GetOptionsProperty
, SetOptionsProperty
,
2893 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, nsnull
2896 #ifdef NS_TRACE_MALLOC
2898 #include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
2906 #include "nsTraceMalloc.h"
2909 CheckUniversalXPConnectForTraceMalloc(JSContext
*cx
)
2911 PRBool hasCap
= PR_FALSE
;
2912 nsresult rv
= nsContentUtils::GetSecurityManager()->
2913 IsCapabilityEnabled("UniversalXPConnect", &hasCap
);
2914 if (NS_SUCCEEDED(rv
) && hasCap
)
2916 JS_ReportError(cx
, "trace-malloc functions require UniversalXPConnect");
2921 TraceMallocDisable(JSContext
*cx
, uintN argc
, jsval
*vp
)
2923 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2926 NS_TraceMallocDisable();
2927 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2932 TraceMallocEnable(JSContext
*cx
, uintN argc
, jsval
*vp
)
2934 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2937 NS_TraceMallocEnable();
2938 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2943 TraceMallocOpenLogFile(JSContext
*cx
, uintN argc
, jsval
*vp
)
2948 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2954 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
2957 JSAutoByteString
filename(cx
, str
);
2960 fd
= open(filename
.ptr(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
2962 JS_ReportError(cx
, "can't open %s: %s", filename
.ptr(), strerror(errno
));
2966 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(fd
));
2971 TraceMallocChangeLogFD(JSContext
*cx
, uintN argc
, jsval
*vp
)
2975 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2981 if (!JS_ValueToECMAInt32(cx
, JS_ARGV(cx
, vp
)[0], &fd
))
2983 oldfd
= NS_TraceMallocChangeLogFD(fd
);
2985 JS_ReportOutOfMemory(cx
);
2989 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(oldfd
));
2994 TraceMallocCloseLogFD(JSContext
*cx
, uintN argc
, jsval
*vp
)
2998 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3001 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3004 if (!JS_ValueToECMAInt32(cx
, JS_ARGV(cx
, vp
)[0], &fd
))
3006 NS_TraceMallocCloseLogFD((int) fd
);
3011 TraceMallocLogTimestamp(JSContext
*cx
, uintN argc
, jsval
*vp
)
3013 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3016 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
3019 JSAutoByteString
caption(cx
, str
);
3022 NS_TraceMallocLogTimestamp(caption
.ptr());
3023 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3028 TraceMallocDumpAllocations(JSContext
*cx
, uintN argc
, jsval
*vp
)
3030 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3033 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
3036 JSAutoByteString
pathname(cx
, str
);
3039 if (NS_TraceMallocDumpAllocations(pathname
.ptr()) < 0) {
3040 JS_ReportError(cx
, "can't dump to %s: %s", pathname
.ptr(), strerror(errno
));
3043 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3047 static JSFunctionSpec TraceMallocFunctions
[] = {
3048 {"TraceMallocDisable", TraceMallocDisable
, 0, 0},
3049 {"TraceMallocEnable", TraceMallocEnable
, 0, 0},
3050 {"TraceMallocOpenLogFile", TraceMallocOpenLogFile
, 1, 0},
3051 {"TraceMallocChangeLogFD", TraceMallocChangeLogFD
, 1, 0},
3052 {"TraceMallocCloseLogFD", TraceMallocCloseLogFD
, 1, 0},
3053 {"TraceMallocLogTimestamp", TraceMallocLogTimestamp
, 1, 0},
3054 {"TraceMallocDumpAllocations", TraceMallocDumpAllocations
, 1, 0},
3055 {nsnull
, nsnull
, 0, 0}
3058 #endif /* NS_TRACE_MALLOC */
3065 IsJProfAction(struct sigaction
*action
)
3067 return (action
->sa_sigaction
&&
3068 action
->sa_flags
== (SA_RESTART
| SA_SIGINFO
));
3071 void NS_JProfStartProfiling();
3072 void NS_JProfStopProfiling();
3075 JProfStartProfilingJS(JSContext
*cx
, uintN argc
, jsval
*vp
)
3077 NS_JProfStartProfiling();
3081 void NS_JProfStartProfiling()
3083 // Figure out whether we're dealing with SIGPROF, SIGALRM, or
3084 // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
3086 struct sigaction action
;
3088 sigaction(SIGALRM
, nsnull
, &action
);
3089 if (IsJProfAction(&action
)) {
3090 printf("Beginning real-time jprof profiling.\n");
3095 sigaction(SIGPROF
, nsnull
, &action
);
3096 if (IsJProfAction(&action
)) {
3097 printf("Beginning process-time jprof profiling.\n");
3102 sigaction(SIGPOLL
, nsnull
, &action
);
3103 if (IsJProfAction(&action
)) {
3104 printf("Beginning rtc-based jprof profiling.\n");
3109 printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
3113 JProfStopProfilingJS(JSContext
*cx
, uintN argc
, jsval
*vp
)
3115 NS_JProfStopProfiling();
3120 NS_JProfStopProfiling()
3123 printf("Stopped jprof profiling.\n");
3126 static JSFunctionSpec JProfFunctions
[] = {
3127 {"JProfStartProfiling", JProfStartProfilingJS
, 0, 0},
3128 {"JProfStopProfiling", JProfStopProfilingJS
, 0, 0},
3129 {nsnull
, nsnull
, 0, 0}
3132 #endif /* defined(MOZ_JPROF) */
3134 #ifdef MOZ_CALLGRIND
3135 static JSFunctionSpec CallgrindFunctions
[] = {
3136 {"startCallgrind", js_StartCallgrind
, 0, 0},
3137 {"stopCallgrind", js_StopCallgrind
, 0, 0},
3138 {"dumpCallgrind", js_DumpCallgrind
, 1, 0},
3139 {nsnull
, nsnull
, 0, 0}
3144 static JSFunctionSpec VtuneFunctions
[] = {
3145 {"startVtune", js_StartVtune
, 1, 0},
3146 {"stopVtune", js_StopVtune
, 0, 0},
3147 {"pauseVtune", js_PauseVtune
, 0, 0},
3148 {"resumeVtune", js_ResumeVtune
, 0, 0},
3149 {nsnull
, nsnull
, 0, 0}
3154 static JSFunctionSpec EthogramFunctions
[] = {
3155 {"initEthogram", js_InitEthogram
, 0, 0},
3156 {"shutdownEthogram", js_ShutdownEthogram
, 0, 0},
3157 {nsnull
, nsnull
, 0, 0}
3162 nsJSContext::InitClasses(void *aGlobalObj
)
3164 nsresult rv
= NS_OK
;
3166 JSObject
*globalObj
= static_cast<JSObject
*>(aGlobalObj
);
3168 rv
= InitializeExternalClasses();
3169 NS_ENSURE_SUCCESS(rv
, rv
);
3171 JSAutoRequest
ar(mContext
);
3173 // Initialize the options object and set default options in mContext
3174 JSObject
*optionsObj
= ::JS_DefineObject(mContext
, globalObj
, "_options",
3175 &OptionsClass
, nsnull
, 0);
3177 ::JS_DefineProperties(mContext
, optionsObj
, OptionsProperties
)) {
3178 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
3180 rv
= NS_ERROR_FAILURE
;
3183 // Attempt to initialize profiling functions
3184 ::JS_DefineProfilingFunctions(mContext
, globalObj
);
3186 #ifdef NS_TRACE_MALLOC
3187 // Attempt to initialize TraceMalloc functions
3188 ::JS_DefineFunctions(mContext
, globalObj
, TraceMallocFunctions
);
3192 // Attempt to initialize JProf functions
3193 ::JS_DefineFunctions(mContext
, globalObj
, JProfFunctions
);
3196 #ifdef MOZ_CALLGRIND
3197 // Attempt to initialize Callgrind functions
3198 ::JS_DefineFunctions(mContext
, globalObj
, CallgrindFunctions
);
3202 // Attempt to initialize Vtune functions
3203 ::JS_DefineFunctions(mContext
, globalObj
, VtuneFunctions
);
3207 // Attempt to initialize Ethogram functions
3208 ::JS_DefineFunctions(mContext
, globalObj
, EthogramFunctions
);
3211 JSOptionChangedCallback(js_options_dot_str
, this);
3217 nsJSContext::ClearScope(void *aGlobalObj
, PRBool aClearFromProtoChain
)
3219 // Push our JSContext on our thread's context stack.
3220 nsCOMPtr
<nsIJSContextStack
> stack
=
3221 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
3222 if (stack
&& NS_FAILED(stack
->Push(mContext
))) {
3227 JSObject
*obj
= (JSObject
*)aGlobalObj
;
3228 JSAutoRequest
ar(mContext
);
3230 JSAutoEnterCompartment ac
;
3231 ac
.enterAndIgnoreErrors(mContext
, obj
);
3233 // Grab a reference to the window property, which is the outer
3234 // window, so that we can re-define it once we've cleared
3235 // scope. This is what keeps the outer window alive in cases where
3236 // nothing else does.
3238 if (!JS_GetProperty(mContext
, obj
, "window", &window
)) {
3239 window
= JSVAL_VOID
;
3241 JS_ClearPendingException(mContext
);
3244 JS_ClearScope(mContext
, obj
);
3245 if (xpc::WrapperFactory::IsXrayWrapper(obj
)) {
3246 JS_ClearScope(mContext
, &obj
->getProxyExtra().toObject());
3249 if (window
!= JSVAL_VOID
) {
3250 if (!JS_DefineProperty(mContext
, obj
, "window", window
,
3251 JS_PropertyStub
, JS_PropertyStub
,
3252 JSPROP_ENUMERATE
| JSPROP_READONLY
|
3253 JSPROP_PERMANENT
)) {
3254 JS_ClearPendingException(mContext
);
3258 if (!obj
->getParent()) {
3259 JS_ClearRegExpStatics(mContext
, obj
);
3262 // Always clear watchpoints, to deal with two cases:
3263 // 1. The first document for this window is loading, and a miscreant has
3264 // preset watchpoints on the window object in order to attack the new
3265 // document's privileged information.
3266 // 2. A document loaded and used watchpoints on its own window, leaving
3267 // them set until the next document loads. We must clean up window
3268 // watchpoints here.
3269 // Watchpoints set on document and subordinate objects are all cleared
3270 // when those sub-window objects are finalized, after JS_ClearScope and
3271 // a GC run that finds them to be garbage.
3272 ::JS_ClearWatchPointsForObject(mContext
, obj
);
3274 // Since the prototype chain is shared between inner and outer (and
3275 // stays with the inner), we don't clear things from the prototype
3276 // chain when we're clearing an outer window whose current inner we
3278 if (aClearFromProtoChain
) {
3279 nsWindowSH::InvalidateGlobalScopePolluter(mContext
, obj
);
3281 // Clear up obj's prototype chain, but not Object.prototype.
3282 for (JSObject
*o
= ::JS_GetPrototype(mContext
, obj
), *next
;
3283 o
&& (next
= ::JS_GetPrototype(mContext
, o
)); o
= next
)
3284 ::JS_ClearScope(mContext
, o
);
3294 nsJSContext::WillInitializeContext()
3296 mIsInitialized
= PR_FALSE
;
3300 nsJSContext::DidInitializeContext()
3302 mIsInitialized
= PR_TRUE
;
3306 nsJSContext::IsContextInitialized()
3308 return mIsInitialized
;
3312 nsJSContext::FinalizeContext()
3320 FireGCTimer(PR_FALSE
);
3324 nsJSContext::ScriptEvaluated(PRBool aTerminated
)
3326 if (aTerminated
&& mTerminations
) {
3327 // Make sure to null out mTerminations before doing anything that
3328 // might cause new termination funcs to be added!
3329 nsJSContext::TerminationFuncClosure
* start
= mTerminations
;
3330 mTerminations
= nsnull
;
3332 for (nsJSContext::TerminationFuncClosure
* cur
= start
;
3335 (*(cur
->mTerminationFunc
))(cur
->mTerminationFuncArg
);
3341 if (mContext
->runtime
->gcZeal
>= 2) {
3342 JS_MaybeGC(mContext
);
3347 mOperationCallbackTime
= 0;
3348 mModalStateTime
= 0;
3353 nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc
,
3356 NS_PRECONDITION(JS_IsRunning(mContext
), "should be executing script");
3358 nsJSContext::TerminationFuncClosure
* newClosure
=
3359 new nsJSContext::TerminationFuncClosure(aFunc
, aRef
, mTerminations
);
3361 return NS_ERROR_OUT_OF_MEMORY
;
3364 mTerminations
= newClosure
;
3369 nsJSContext::GetScriptsEnabled()
3371 return mScriptsEnabled
;
3375 nsJSContext::SetScriptsEnabled(PRBool aEnabled
, PRBool aFireTimeouts
)
3377 // eeek - this seems the wrong way around - the global should callback
3378 // into each context, so every language is disabled.
3379 mScriptsEnabled
= aEnabled
;
3381 nsIScriptGlobalObject
*global
= GetGlobalObject();
3384 global
->SetScriptsEnabled(aEnabled
, aFireTimeouts
);
3390 nsJSContext::GetProcessingScriptTag()
3392 return mProcessingScriptTag
;
3396 nsJSContext::SetProcessingScriptTag(PRBool aFlag
)
3398 mProcessingScriptTag
= aFlag
;
3402 nsJSContext::GetExecutingScript()
3404 return JS_IsRunning(mContext
) || mExecuteDepth
> 0;
3408 nsJSContext::SetGCOnDestruction(PRBool aGCOnDestruction
)
3410 mGCOnDestruction
= aGCOnDestruction
;
3414 nsJSContext::ScriptExecuted()
3416 ScriptEvaluated(!::JS_IsRunning(mContext
));
3423 nsJSContext::CC(nsICycleCollectorListener
*aListener
)
3425 NS_TIME_FUNCTION_MIN(1.0);
3429 printf("Will run cycle collector (%i), %lldms since previous.\n",
3430 sCCollectCount
, (PR_Now() - sPreviousCCTime
) / PR_USEC_PER_MSEC
);
3432 sPreviousCCTime
= PR_Now();
3433 sDelayedCCollectCount
= 0;
3434 sCCSuspectChanges
= 0;
3435 // nsCycleCollector_collect() no longer forces a JS garbage collection,
3436 // so we have to do it ourselves here.
3437 if (nsContentUtils::XPConnect()) {
3438 nsContentUtils::XPConnect()->GarbageCollect();
3440 sCollectedObjectsCounts
= nsCycleCollector_collect(aListener
);
3441 sCCSuspectedCount
= nsCycleCollector_suspectedCount();
3442 if (nsJSRuntime::sRuntime
) {
3443 sSavedGCCount
= JS_GetGCParameter(nsJSRuntime::sRuntime
, JSGC_NUMBER
);
3446 printf("Collected %u objects, %u suspected objects, took %lldms\n",
3447 sCollectedObjectsCounts
, sCCSuspectedCount
,
3448 (PR_Now() - sPreviousCCTime
) / PR_USEC_PER_MSEC
);
3452 static inline uint32
3453 GetGCRunsSinceLastCC()
3455 // To avoid crash if nsJSRuntime is not properly initialized.
3456 // See the bug 474586
3457 if (!nsJSRuntime::sRuntime
)
3460 // Since JS_GetGCParameter() and sSavedGCCount are unsigned, the following
3461 // gives the correct result even when the GC counter wraps around
3462 // UINT32_MAX since the last call to JS_GetGCParameter().
3463 return JS_GetGCParameter(nsJSRuntime::sRuntime
, JSGC_NUMBER
) -
3469 nsJSContext::MaybeCC(PRBool aHigherProbability
)
3471 ++sDelayedCCollectCount
;
3473 // Don't check suspected count if CC will be called anyway.
3474 if (sCCSuspectChanges
<= NS_MIN_SUSPECT_CHANGES
||
3475 GetGCRunsSinceLastCC() <= NS_MAX_GC_COUNT
) {
3477 PRTime now
= PR_Now();
3479 PRUint32 suspected
= nsCycleCollector_suspectedCount();
3481 printf("%u suspected objects (%lldms), sCCSuspectedCount %u\n",
3482 suspected
, (PR_Now() - now
) / PR_USEC_PER_MSEC
,
3485 // Update only when suspected count has increased.
3486 if (suspected
> sCCSuspectedCount
) {
3487 sCCSuspectChanges
+= (suspected
- sCCSuspectedCount
);
3488 sCCSuspectedCount
= suspected
;
3492 printf("sCCSuspectChanges %u, GC runs %u\n",
3493 sCCSuspectChanges
, GetGCRunsSinceLastCC());
3496 // Increase the probability also if the previous call to cycle collector
3497 // collected something.
3498 if (aHigherProbability
||
3499 sCollectedObjectsCounts
> NS_COLLECTED_OBJECTS_LIMIT
) {
3500 sDelayedCCollectCount
*= NS_PROBABILITY_MULTIPLIER
;
3501 } else if (!sUserIsActive
&& sCCSuspectChanges
> NS_MAX_SUSPECT_CHANGES
) {
3502 // If user is inactive and there are lots of new suspected objects,
3503 // increase the probability for cycle collection.
3504 sDelayedCCollectCount
+= (sCCSuspectChanges
/ NS_MAX_SUSPECT_CHANGES
);
3508 (sDelayedCCollectCount
> NS_MAX_DELAYED_CCOLLECT
) &&
3509 ((sCCSuspectChanges
> NS_MIN_SUSPECT_CHANGES
&&
3510 GetGCRunsSinceLastCC() > NS_MAX_GC_COUNT
) ||
3511 (sCCSuspectChanges
> NS_MAX_SUSPECT_CHANGES
))) {
3512 return IntervalCC();
3519 nsJSContext::CCIfUserInactive()
3521 if (sUserIsActive
) {
3530 nsJSContext::MaybeCCIfUserInactive()
3532 if (!sUserIsActive
) {
3539 nsJSContext::IntervalCC()
3541 if ((PR_Now() - sPreviousCCTime
) >=
3542 PRTime(NS_MIN_CC_INTERVAL
* PR_USEC_PER_MSEC
)) {
3543 nsJSContext::CC(nsnull
);
3547 printf("Running CC was delayed because of NS_MIN_CC_INTERVAL.\n");
3554 GCTimerFired(nsITimer
*aTimer
, void *aClosure
)
3556 NS_RELEASE(sGCTimer
);
3558 if (sPendingLoadCount
== 0 || sLoadInProgressGCTimer
) {
3559 sLoadInProgressGCTimer
= PR_FALSE
;
3561 // Reset sPendingLoadCount in case the timer that fired was a
3562 // timer we scheduled due to a normal GC timer firing while
3563 // documents were loading. If this happens we're waiting for a
3564 // document that is taking a long time to load, and we effectively
3565 // ignore the fact that the currently loading documents are still
3566 // loading and move on as if they weren't.
3567 sPendingLoadCount
= 0;
3569 nsJSContext::CCIfUserInactive();
3571 nsJSContext::FireGCTimer(PR_TRUE
);
3574 sReadyForGC
= PR_TRUE
;
3579 nsJSContext::LoadStart()
3581 ++sPendingLoadCount
;
3586 nsJSContext::LoadEnd()
3588 // sPendingLoadCount is not a well managed load counter (and doesn't
3589 // need to be), so make sure we don't make it wrap backwards here.
3590 if (sPendingLoadCount
> 0) {
3591 --sPendingLoadCount
;
3594 if (!sPendingLoadCount
&& sLoadInProgressGCTimer
) {
3596 NS_RELEASE(sGCTimer
);
3597 sLoadInProgressGCTimer
= PR_FALSE
;
3605 nsJSContext::FireGCTimer(PRBool aLoadInProgress
)
3608 // There's already a timer for GC'ing, just return
3612 CallCreateInstance("@mozilla.org/timer;1", &sGCTimer
);
3615 NS_WARNING("Failed to create timer");
3617 // Reset sLoadInProgressGCTimer since we're not able to fire the
3619 sLoadInProgressGCTimer
= PR_FALSE
;
3625 static PRBool first
= PR_TRUE
;
3627 sGCTimer
->InitWithFuncCallback(GCTimerFired
, nsnull
,
3628 first
? NS_FIRST_GC_DELAY
:
3629 aLoadInProgress
? NS_LOAD_IN_PROCESS_GC_DELAY
:
3631 nsITimer::TYPE_ONE_SHOT
);
3633 sLoadInProgressGCTimer
= aLoadInProgress
;
3639 DOMGCCallback(JSContext
*cx
, JSGCStatus status
)
3641 JSBool result
= gOldJSGCCallback
? gOldJSGCCallback(cx
, status
) : JS_TRUE
;
3643 if (status
== JSGC_BEGIN
&& !NS_IsMainThread())
3649 // Script object mananagement - note duplicate implementation
3650 // in nsJSRuntime below...
3652 nsJSContext::HoldScriptObject(void* aScriptObject
)
3654 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3655 if (! nsJSRuntime::sRuntime
) {
3656 NS_NOTREACHED("couldn't add GC root - no runtime");
3657 return NS_ERROR_FAILURE
;
3660 ::JS_LockGCThingRT(nsJSRuntime::sRuntime
, aScriptObject
);
3665 nsJSContext::DropScriptObject(void* aScriptObject
)
3667 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3668 if (! nsJSRuntime::sRuntime
) {
3669 NS_NOTREACHED("couldn't remove GC root");
3670 return NS_ERROR_FAILURE
;
3673 ::JS_UnlockGCThingRT(nsJSRuntime::sRuntime
, aScriptObject
);
3678 nsJSContext::ReportPendingException()
3680 // set aside the frame chain, since it has nothing to do with the
3681 // exception we're reporting.
3682 if (mIsInitialized
&& ::JS_IsExceptionPending(mContext
)) {
3683 JSStackFrame
* frame
= JS_SaveFrameChain(mContext
);
3684 ::JS_ReportPendingException(mContext
);
3685 JS_RestoreFrameChain(mContext
, frame
);
3689 /**********************************************************************
3690 * nsJSRuntime implementation
3691 *********************************************************************/
3693 // QueryInterface implementation for nsJSRuntime
3694 NS_INTERFACE_MAP_BEGIN(nsJSRuntime
)
3695 NS_INTERFACE_MAP_ENTRY(nsIScriptRuntime
)
3696 NS_INTERFACE_MAP_END
3699 NS_IMPL_ADDREF(nsJSRuntime
)
3700 NS_IMPL_RELEASE(nsJSRuntime
)
3703 nsJSRuntime::CreateContext(nsIScriptContext
**aContext
)
3705 nsCOMPtr
<nsIScriptContext
> scriptContext
;
3707 *aContext
= new nsJSContext(sRuntime
);
3708 NS_ENSURE_TRUE(*aContext
, NS_ERROR_OUT_OF_MEMORY
);
3709 NS_ADDREF(*aContext
);
3714 nsJSRuntime::ParseVersion(const nsString
&aVersionStr
, PRUint32
*flags
)
3716 NS_PRECONDITION(flags
, "Null flags param?");
3717 JSVersion jsVersion
= JSVERSION_UNKNOWN
;
3718 if (aVersionStr
.Length() != 3 || aVersionStr
[0] != '1' || aVersionStr
[1] != '.')
3719 jsVersion
= JSVERSION_UNKNOWN
;
3720 else switch (aVersionStr
[2]) {
3721 case '0': jsVersion
= JSVERSION_1_0
; break;
3722 case '1': jsVersion
= JSVERSION_1_1
; break;
3723 case '2': jsVersion
= JSVERSION_1_2
; break;
3724 case '3': jsVersion
= JSVERSION_1_3
; break;
3725 case '4': jsVersion
= JSVERSION_1_4
; break;
3726 case '5': jsVersion
= JSVERSION_1_5
; break;
3727 case '6': jsVersion
= JSVERSION_1_6
; break;
3728 case '7': jsVersion
= JSVERSION_1_7
; break;
3729 case '8': jsVersion
= JSVERSION_1_8
; break;
3730 default: jsVersion
= JSVERSION_UNKNOWN
;
3732 *flags
= (PRUint32
)jsVersion
;
3738 nsJSRuntime::Startup()
3740 // initialize all our statics, so that we can restart XPCOM
3741 sDelayedCCollectCount
= 0;
3743 sUserIsActive
= PR_FALSE
;
3744 sPreviousCCTime
= PR_Now();
3745 sCollectedObjectsCounts
= 0;
3747 sCCSuspectChanges
= 0;
3748 sCCSuspectedCount
= 0;
3750 sReadyForGC
= PR_FALSE
;
3751 sLoadInProgressGCTimer
= PR_FALSE
;
3752 sPendingLoadCount
= 0;
3753 gNameSpaceManager
= nsnull
;
3754 sRuntimeService
= nsnull
;
3756 gOldJSGCCallback
= nsnull
;
3757 sIsInitialized
= PR_FALSE
;
3758 sDidShutdown
= PR_FALSE
;
3760 sSecurityManager
= nsnull
;
3764 MaxScriptRunTimePrefChangedCallback(const char *aPrefName
, void *aClosure
)
3766 // Default limit on script run time to 10 seconds. 0 means let
3767 // scripts run forever.
3768 PRBool isChromePref
=
3769 strcmp(aPrefName
, "dom.max_chrome_script_run_time") == 0;
3770 PRInt32 time
= nsContentUtils::GetIntPref(aPrefName
, isChromePref
? 20 : 10);
3774 // Let scripts run for a really, really long time.
3775 t
= LL_INIT(0x40000000, 0);
3777 t
= time
* PR_USEC_PER_SEC
;
3781 sMaxChromeScriptRunTime
= t
;
3783 sMaxScriptRunTime
= t
;
3790 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3792 PRBool reportAll
= nsContentUtils::GetBoolPref(aPrefName
, PR_FALSE
);
3793 nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll
);
3798 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3800 PRInt32 highwatermark
= nsContentUtils::GetIntPref(aPrefName
, 128);
3802 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_MALLOC_BYTES
,
3803 highwatermark
* 1024L * 1024L);
3808 SetMemoryMaxPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3810 PRInt32 pref
= nsContentUtils::GetIntPref(aPrefName
, -1);
3811 // handle overflow and negative pref values
3812 PRUint32 max
= (pref
<= 0 || pref
>= 0x1000) ? -1 : (PRUint32
)pref
* 1024 * 1024;
3813 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_BYTES
, max
);
3818 SetMemoryGCFrequencyPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3820 PRInt32 triggerFactor
= nsContentUtils::GetIntPref(aPrefName
, 300);
3821 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_TRIGGER_FACTOR
, triggerFactor
);
3826 SetMemoryGCModePrefChangedCallback(const char* aPrefName
, void* aClosure
)
3828 PRBool enableCompartmentGC
= nsContentUtils::GetBoolPref(aPrefName
);
3829 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MODE
, enableCompartmentGC
3830 ? JSGC_MODE_COMPARTMENT
3831 : JSGC_MODE_GLOBAL
);
3835 static JSPrincipals
*
3836 ObjectPrincipalFinder(JSContext
*cx
, JSObject
*obj
)
3838 if (!sSecurityManager
)
3841 nsCOMPtr
<nsIPrincipal
> principal
;
3843 sSecurityManager
->GetObjectPrincipal(cx
, obj
,
3844 getter_AddRefs(principal
));
3846 if (NS_FAILED(rv
) || !principal
) {
3850 JSPrincipals
*jsPrincipals
= nsnull
;
3851 principal
->GetJSPrincipals(cx
, &jsPrincipals
);
3853 // nsIPrincipal::GetJSPrincipals() returns a strong reference to the
3854 // JS principals, but the caller of this function expects a weak
3855 // reference. So we need to release here.
3857 JSPRINCIPALS_DROP(cx
, jsPrincipals
);
3859 return jsPrincipals
;
3863 DOMReadStructuredClone(JSContext
* cx
,
3864 JSStructuredCloneReader
* reader
,
3869 // We don't currently support any extensions to structured cloning.
3870 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3875 DOMWriteStructuredClone(JSContext
* cx
,
3876 JSStructuredCloneWriter
* writer
,
3880 // We don't currently support any extensions to structured cloning.
3881 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3886 DOMStructuredCloneError(JSContext
* cx
,
3889 // We don't currently support any extensions to structured cloning.
3890 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3897 if (sIsInitialized
) {
3898 if (!nsContentUtils::XPConnect())
3899 return NS_ERROR_NOT_AVAILABLE
;
3904 nsresult rv
= CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
,
3906 NS_ENSURE_SUCCESS(rv
, rv
);
3908 rv
= CallGetService(kJSRuntimeServiceContractID
, &sRuntimeService
);
3909 // get the JSRuntime from the runtime svc, if possible
3910 NS_ENSURE_SUCCESS(rv
, rv
);
3912 rv
= sRuntimeService
->GetRuntime(&sRuntime
);
3913 NS_ENSURE_SUCCESS(rv
, rv
);
3915 // Let's make sure that our main thread is the same as the xpcom main thread.
3916 NS_ASSERTION(NS_IsMainThread(), "bad");
3918 NS_ASSERTION(!gOldJSGCCallback
,
3919 "nsJSRuntime initialized more than once");
3921 sSavedGCCount
= JS_GetGCParameter(nsJSRuntime::sRuntime
, JSGC_NUMBER
);
3923 // Save the old GC callback to chain to it, for GC-observing generality.
3924 gOldJSGCCallback
= ::JS_SetGCCallbackRT(sRuntime
, DOMGCCallback
);
3926 JSSecurityCallbacks
*callbacks
= JS_GetRuntimeSecurityCallbacks(sRuntime
);
3927 NS_ASSERTION(callbacks
, "SecMan should have set security callbacks!");
3929 callbacks
->findObjectPrincipals
= ObjectPrincipalFinder
;
3931 // Set up the structured clone callbacks.
3932 static JSStructuredCloneCallbacks cloneCallbacks
= {
3933 DOMReadStructuredClone
,
3934 DOMWriteStructuredClone
,
3935 DOMStructuredCloneError
3937 JS_SetStructuredCloneCallbacks(sRuntime
, &cloneCallbacks
);
3939 // Set these global xpconnect options...
3940 nsContentUtils::RegisterPrefCallback("dom.max_script_run_time",
3941 MaxScriptRunTimePrefChangedCallback
,
3943 MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull
);
3945 nsContentUtils::RegisterPrefCallback("dom.max_chrome_script_run_time",
3946 MaxScriptRunTimePrefChangedCallback
,
3948 MaxScriptRunTimePrefChangedCallback("dom.max_chrome_script_run_time",
3951 nsContentUtils::RegisterPrefCallback("dom.report_all_js_exceptions",
3952 ReportAllJSExceptionsPrefChangedCallback
,
3954 ReportAllJSExceptionsPrefChangedCallback("dom.report_all_js_exceptions",
3957 nsContentUtils::RegisterPrefCallback("javascript.options.mem.high_water_mark",
3958 SetMemoryHighWaterMarkPrefChangedCallback
,
3960 SetMemoryHighWaterMarkPrefChangedCallback("javascript.options.mem.high_water_mark",
3963 nsContentUtils::RegisterPrefCallback("javascript.options.mem.max",
3964 SetMemoryMaxPrefChangedCallback
,
3966 SetMemoryMaxPrefChangedCallback("javascript.options.mem.max",
3969 nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_frequency",
3970 SetMemoryGCFrequencyPrefChangedCallback
,
3972 SetMemoryGCFrequencyPrefChangedCallback("javascript.options.mem.gc_frequency",
3975 nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_per_compartment",
3976 SetMemoryGCModePrefChangedCallback
,
3978 SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_per_compartment",
3981 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
3983 return NS_ERROR_FAILURE
;
3984 nsIObserver
* activityObserver
= new nsUserActivityObserver();
3985 NS_ENSURE_TRUE(activityObserver
, NS_ERROR_OUT_OF_MEMORY
);
3986 obs
->AddObserver(activityObserver
, "user-interaction-inactive", PR_FALSE
);
3987 obs
->AddObserver(activityObserver
, "user-interaction-active", PR_FALSE
);
3988 obs
->AddObserver(activityObserver
, "xpcom-shutdown", PR_FALSE
);
3990 nsIObserver
* ccMemPressureObserver
= new nsCCMemoryPressureObserver();
3991 NS_ENSURE_TRUE(ccMemPressureObserver
, NS_ERROR_OUT_OF_MEMORY
);
3992 obs
->AddObserver(ccMemPressureObserver
, "memory-pressure", PR_FALSE
);
3994 sIsInitialized
= PR_TRUE
;
4000 nsScriptNameSpaceManager
*
4001 nsJSRuntime::GetNameSpaceManager()
4006 if (!gNameSpaceManager
) {
4007 gNameSpaceManager
= new nsScriptNameSpaceManager
;
4008 NS_ADDREF(gNameSpaceManager
);
4010 nsresult rv
= gNameSpaceManager
->Init();
4011 NS_ENSURE_SUCCESS(rv
, nsnull
);
4014 return gNameSpaceManager
;
4019 nsJSRuntime::Shutdown()
4022 // We're being shut down, if we have a GC timer scheduled, cancel
4023 // it. The DOM factory will do one final GC once it's shut down.
4027 NS_RELEASE(sGCTimer
);
4029 sLoadInProgressGCTimer
= PR_FALSE
;
4032 NS_IF_RELEASE(gNameSpaceManager
);
4034 if (!sContextCount
) {
4035 // We're being shutdown, and there are no more contexts
4036 // alive, release the JS runtime service and the security manager.
4038 if (sRuntimeService
&& sSecurityManager
) {
4039 JSSecurityCallbacks
*callbacks
= JS_GetRuntimeSecurityCallbacks(sRuntime
);
4041 NS_ASSERTION(callbacks
->findObjectPrincipals
== ObjectPrincipalFinder
,
4042 "Fighting over the findObjectPrincipals callback!");
4043 callbacks
->findObjectPrincipals
= NULL
;
4046 NS_IF_RELEASE(sRuntimeService
);
4047 NS_IF_RELEASE(sSecurityManager
);
4050 sDidShutdown
= PR_TRUE
;
4053 // Script object mananagement - note duplicate implementation
4054 // in nsJSContext above...
4056 nsJSRuntime::HoldScriptObject(void* aScriptObject
)
4058 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
4060 NS_NOTREACHED("couldn't remove GC root - no runtime");
4061 return NS_ERROR_FAILURE
;
4064 ::JS_LockGCThingRT(sRuntime
, aScriptObject
);
4069 nsJSRuntime::DropScriptObject(void* aScriptObject
)
4071 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
4073 NS_NOTREACHED("couldn't remove GC root");
4074 return NS_ERROR_FAILURE
;
4077 ::JS_UnlockGCThingRT(sRuntime
, aScriptObject
);
4081 // A factory for the runtime.
4082 nsresult
NS_CreateJSRuntime(nsIScriptRuntime
**aRuntime
)
4084 nsresult rv
= nsJSRuntime::Init();
4085 NS_ENSURE_SUCCESS(rv
, rv
);
4087 *aRuntime
= new nsJSRuntime();
4088 if (*aRuntime
== nsnull
)
4089 return NS_ERROR_OUT_OF_MEMORY
;
4090 NS_IF_ADDREF(*aRuntime
);
4094 // A fast-array class for JS. This class supports both nsIJSScriptArray and
4095 // nsIArray. If it is JS itself providing and consuming this class, all work
4096 // can be done via nsIJSScriptArray, and avoid the conversion of elements
4097 // to/from nsISupports.
4098 // When consumed by non-JS (eg, another script language), conversion is done
4100 class nsJSArgArray
: public nsIJSArgArray
, public nsIArray
{
4102 nsJSArgArray(JSContext
*aContext
, PRUint32 argc
, jsval
*argv
, nsresult
*prv
);
4105 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
4106 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray
,
4113 nsresult
GetArgs(PRUint32
*argc
, void **argv
);
4115 void ReleaseJSObjects();
4118 JSContext
*mContext
;
4123 nsJSArgArray::nsJSArgArray(JSContext
*aContext
, PRUint32 argc
, jsval
*argv
,
4129 // copy the array - we don't know its lifetime, and ours is tied to xpcom
4130 // refcounting. Alloc zero'd array so cleanup etc is safe.
4132 mArgv
= (jsval
*) PR_CALLOC(argc
* sizeof(jsval
));
4134 *prv
= NS_ERROR_OUT_OF_MEMORY
;
4139 // Callers are allowed to pass in a null argv even for argc > 0. They can
4140 // then use GetArgs to initialize the values.
4142 for (PRUint32 i
= 0; i
< argc
; ++i
)
4146 *prv
= argc
> 0 ? NS_HOLD_JS_OBJECTS(this, nsJSArgArray
) : NS_OK
;
4149 nsJSArgArray::~nsJSArgArray()
4155 nsJSArgArray::ReleaseJSObjects()
4158 NS_DROP_JS_OBJECTS(this, nsJSArgArray
);
4165 // QueryInterface implementation for nsJSArgArray
4166 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray
)
4167 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSArgArray
)
4168 tmp
->ReleaseJSObjects();
4169 NS_IMPL_CYCLE_COLLECTION_ROOT_END
4170 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsJSArgArray
)
4171 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray
)
4172 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
4173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
4175 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray
)
4176 jsval
*argv
= tmp
->mArgv
;
4179 for (end
= argv
+ tmp
->mArgc
; argv
< end
; ++argv
) {
4180 if (JSVAL_IS_GCTHING(*argv
))
4181 NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT
,
4182 JSVAL_TO_GCTHING(*argv
))
4185 NS_IMPL_CYCLE_COLLECTION_TRACE_END
4187 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray
)
4188 NS_INTERFACE_MAP_ENTRY(nsIArray
)
4189 NS_INTERFACE_MAP_ENTRY(nsIJSArgArray
)
4190 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSArgArray
)
4191 NS_INTERFACE_MAP_END
4193 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSArgArray
, nsIJSArgArray
)
4194 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSArgArray
, nsIJSArgArray
)
4197 nsJSArgArray::GetArgs(PRUint32
*argc
, void **argv
)
4200 NS_WARNING("nsJSArgArray has no argv!");
4201 return NS_ERROR_UNEXPECTED
;
4203 *argv
= (void *)mArgv
;
4209 NS_IMETHODIMP
nsJSArgArray::GetLength(PRUint32
*aLength
)
4215 /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
4216 NS_IMETHODIMP
nsJSArgArray::QueryElementAt(PRUint32 index
, const nsIID
& uuid
, void * *result
)
4220 return NS_ERROR_INVALID_ARG
;
4222 if (uuid
.Equals(NS_GET_IID(nsIVariant
)) || uuid
.Equals(NS_GET_IID(nsISupports
))) {
4223 return nsContentUtils::XPConnect()->JSToVariant(mContext
, mArgv
[index
],
4224 (nsIVariant
**)result
);
4226 NS_WARNING("nsJSArgArray only handles nsIVariant");
4227 return NS_ERROR_NO_INTERFACE
;
4230 /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
4231 NS_IMETHODIMP
nsJSArgArray::IndexOf(PRUint32 startIndex
, nsISupports
*element
, PRUint32
*_retval
)
4233 return NS_ERROR_NOT_IMPLEMENTED
;
4236 /* nsISimpleEnumerator enumerate (); */
4237 NS_IMETHODIMP
nsJSArgArray::Enumerate(nsISimpleEnumerator
**_retval
)
4239 return NS_ERROR_NOT_IMPLEMENTED
;
4242 // The factory function
4243 nsresult
NS_CreateJSArgv(JSContext
*aContext
, PRUint32 argc
, void *argv
,
4247 nsJSArgArray
*ret
= new nsJSArgArray(aContext
, argc
,
4248 static_cast<jsval
*>(argv
), &rv
);
4250 return NS_ERROR_OUT_OF_MEMORY
;
4251 if (NS_FAILED(rv
)) {
4255 return ret
->QueryInterface(NS_GET_IID(nsIArray
), (void **)aArray
);