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"
88 #include "xpcpublic.h"
90 #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
93 #include "nsIObjectInputStream.h"
94 #include "nsIObjectOutputStream.h"
95 #include "nsITimelineService.h"
96 #include "nsDOMScriptObjectHolder.h"
98 #include "WrapperFactory.h"
99 #include "nsGlobalWindow.h"
102 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
105 #include "AccessCheck.h"
107 #ifdef MOZ_JSDEBUGGER
108 #include "jsdIDebuggerService.h"
111 // Force PR_LOGGING so we can get JS strict warnings even in release builds
112 #define FORCE_PR_LOG 1
115 #include "prthread.h"
117 #include "mozilla/FunctionTimer.h"
119 const size_t gStackSize
= 8192;
122 static PRLogModuleInfo
* gJSDiagnostics
;
125 // Thank you Microsoft!
132 // The amount of time we wait between a request to GC (due to leaving
133 // a page) and doing the actual GC.
134 #define NS_GC_DELAY 4000 // ms
136 // The amount of time we wait from the first request to GC to actually
137 // doing the first GC.
138 #define NS_FIRST_GC_DELAY 10000 // ms
140 // The amount of time we wait between a request to CC (after GC ran)
141 // and doing the actual CC.
142 #define NS_CC_DELAY 5000 // ms
144 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
146 // if you add statics here, add them to the list in nsJSRuntime::Startup
148 static nsITimer
*sGCTimer
;
149 static nsITimer
*sCCTimer
;
151 // The number of currently pending document loads. This count isn't
152 // guaranteed to always reflect reality and can't easily as we don't
153 // have an easy place to know when a load ends or is interrupted in
154 // all cases. This counter also gets reset if we end up GC'ing while
155 // we're waiting for a slow page to load. IOW, this count may be 0
156 // even when there are pending loads.
157 static PRUint32 sPendingLoadCount
;
158 static PRBool sLoadingInProgress
;
160 static PRBool sPostGCEventsToConsole
;
162 nsScriptNameSpaceManager
*gNameSpaceManager
;
164 static nsIJSRuntimeService
*sRuntimeService
;
165 JSRuntime
*nsJSRuntime::sRuntime
;
167 static const char kJSRuntimeServiceContractID
[] =
168 "@mozilla.org/js/xpc/RuntimeService;1";
170 static JSGCCallback gOldJSGCCallback
;
172 static PRBool sIsInitialized
;
173 static PRBool sDidShutdown
;
175 static PRInt32 sContextCount
;
177 static PRTime sMaxScriptRunTime
;
178 static PRTime sMaxChromeScriptRunTime
;
180 static nsIScriptSecurityManager
*sSecurityManager
;
182 // nsMemoryPressureObserver observes the memory-pressure notifications
183 // and forces a garbage collection and cycle collection when it happens.
185 class nsMemoryPressureObserver
: public nsIObserver
192 NS_IMPL_ISUPPORTS1(nsMemoryPressureObserver
, nsIObserver
)
195 nsMemoryPressureObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
196 const PRUnichar
* aData
)
198 nsJSContext::GarbageCollectNow();
199 nsJSContext::CycleCollectNow();
203 /****************************************************************
204 ************************** AutoFree ****************************
205 ****************************************************************/
209 AutoFree(void *aPtr
) : mPtr(aPtr
) {
213 nsMemory::Free(mPtr
);
222 class nsAutoPoolRelease
{
224 nsAutoPoolRelease(JSArenaPool
*p
, void *m
) : mPool(p
), mMark(m
) {}
225 ~nsAutoPoolRelease() { JS_ARENA_RELEASE(mPool
, mMark
); }
231 // A utility function for script languages to call. Although it looks small,
232 // the use of nsIDocShell and nsPresContext triggers a huge number of
233 // dependencies that most languages would not otherwise need.
234 // XXXmarkh - This function is mis-placed!
236 NS_HandleScriptError(nsIScriptGlobalObject
*aScriptGlobal
,
237 nsScriptErrorEvent
*aErrorEvent
,
238 nsEventStatus
*aStatus
)
240 PRBool called
= PR_FALSE
;
241 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobal
));
242 nsIDocShell
*docShell
= win
? win
->GetDocShell() : nsnull
;
244 nsRefPtr
<nsPresContext
> presContext
;
245 docShell
->GetPresContext(getter_AddRefs(presContext
));
247 static PRInt32 errorDepth
; // Recursion prevention
250 if (presContext
&& errorDepth
< 2) {
251 // Dispatch() must be synchronous for the recursion block
252 // (errorDepth) to work.
253 nsEventDispatcher::Dispatch(win
, presContext
, aErrorEvent
, nsnull
,
262 class ScriptErrorEvent
: public nsRunnable
265 ScriptErrorEvent(nsIScriptGlobalObject
* aScriptGlobal
,
266 PRUint32 aLineNr
, PRUint32 aColumn
, PRUint32 aFlags
,
267 const nsAString
& aErrorMsg
,
268 const nsAString
& aFileName
,
269 const nsAString
& aSourceLine
,
270 PRBool aDispatchEvent
,
272 : mScriptGlobal(aScriptGlobal
), mLineNr(aLineNr
), mColumn(aColumn
),
273 mFlags(aFlags
), mErrorMsg(aErrorMsg
), mFileName(aFileName
),
274 mSourceLine(aSourceLine
), mDispatchEvent(aDispatchEvent
),
280 nsEventStatus status
= nsEventStatus_eIgnore
;
281 // First, notify the DOM that we have a script error.
282 if (mDispatchEvent
) {
283 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
284 nsIDocShell
* docShell
= win
? win
->GetDocShell() : nsnull
;
286 !JSREPORT_IS_WARNING(mFlags
) &&
287 !sHandlingScriptError
) {
288 sHandlingScriptError
= PR_TRUE
; // Recursion prevention
290 nsRefPtr
<nsPresContext
> presContext
;
291 docShell
->GetPresContext(getter_AddRefs(presContext
));
294 nsScriptErrorEvent
errorevent(PR_TRUE
, NS_LOAD_ERROR
);
296 errorevent
.fileName
= mFileName
.get();
298 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(win
));
299 NS_ENSURE_STATE(sop
);
300 nsIPrincipal
* p
= sop
->GetPrincipal();
303 PRBool sameOrigin
= mFileName
.IsVoid();
305 if (p
&& !sameOrigin
) {
306 nsCOMPtr
<nsIURI
> errorURI
;
307 NS_NewURI(getter_AddRefs(errorURI
), mFileName
);
309 // FIXME: Once error reports contain the origin of the
310 // error (principals) we should change this to do the
311 // security check based on the principals and not
312 // URIs. See bug 387476.
313 sameOrigin
= NS_SUCCEEDED(p
->CheckMayLoad(errorURI
, PR_FALSE
));
317 NS_NAMED_LITERAL_STRING(xoriginMsg
, "Script error.");
319 errorevent
.errorMsg
= mErrorMsg
.get();
320 errorevent
.lineNr
= mLineNr
;
322 NS_WARNING("Not same origin error!");
323 errorevent
.errorMsg
= xoriginMsg
.get();
324 errorevent
.lineNr
= 0;
325 // FIXME: once the principal of the script is not tied to
326 // the filename, we can stop using the post-redirect
327 // filename if we want and remove this line. Note that
328 // apparently we can't handle null filenames in the error
329 // event dispatching code.
330 static PRUnichar nullFilename
[] = { PRUnichar(0) };
331 errorevent
.fileName
= nullFilename
;
334 nsEventDispatcher::Dispatch(win
, presContext
, &errorevent
, nsnull
,
338 sHandlingScriptError
= PR_FALSE
;
342 if (status
!= nsEventStatus_eConsumeNoDefault
) {
343 // Make an nsIScriptError and populate it with information from
345 nsCOMPtr
<nsIScriptError
> errorObject
=
346 do_CreateInstance("@mozilla.org/scripterror;1");
348 if (errorObject
!= nsnull
) {
349 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
351 // Set category to chrome or content
352 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptPrincipal
=
353 do_QueryInterface(mScriptGlobal
);
354 NS_ASSERTION(scriptPrincipal
, "Global objects must implement "
355 "nsIScriptObjectPrincipal");
356 nsCOMPtr
<nsIPrincipal
> systemPrincipal
;
357 sSecurityManager
->GetSystemPrincipal(getter_AddRefs(systemPrincipal
));
358 const char * category
=
359 scriptPrincipal
->GetPrincipal() == systemPrincipal
360 ? "chrome javascript"
361 : "content javascript";
363 nsCOMPtr
<nsIScriptError2
> error2(do_QueryInterface(errorObject
));
365 rv
= error2
->InitWithWindowID(mErrorMsg
.get(), mFileName
.get(),
367 mLineNr
, mColumn
, mFlags
,
368 category
, mWindowID
);
370 rv
= errorObject
->Init(mErrorMsg
.get(), mFileName
.get(),
372 mLineNr
, mColumn
, mFlags
,
376 if (NS_SUCCEEDED(rv
)) {
377 nsCOMPtr
<nsIConsoleService
> consoleService
=
378 do_GetService(NS_CONSOLESERVICE_CONTRACTID
, &rv
);
379 if (NS_SUCCEEDED(rv
)) {
380 consoleService
->LogMessage(errorObject
);
389 nsCOMPtr
<nsIScriptGlobalObject
> mScriptGlobal
;
395 nsString mSourceLine
;
396 PRBool mDispatchEvent
;
399 static PRBool sHandlingScriptError
;
402 PRBool
ScriptErrorEvent::sHandlingScriptError
= PR_FALSE
;
404 // NOTE: This function could be refactored to use the above. The only reason
405 // it has not been done is that the code below only fills the error event
406 // after it has a good nsPresContext - whereas using the above function
407 // would involve always filling it. Is that a concern?
409 NS_ScriptErrorReporter(JSContext
*cx
,
411 JSErrorReport
*report
)
413 // We don't want to report exceptions too eagerly, but warnings in the
414 // absence of werror are swallowed whole, so report those now.
415 if (!JSREPORT_IS_WARNING(report
->flags
)) {
416 JSStackFrame
* fp
= nsnull
;
417 while ((fp
= JS_FrameIterator(cx
, &fp
))) {
418 if (JS_IsScriptFrame(cx
, fp
)) {
423 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
425 nsAXPCNativeCallContext
*cc
= nsnull
;
426 xpc
->GetCurrentNativeCallContext(&cc
);
428 nsAXPCNativeCallContext
*prev
= cc
;
429 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
431 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
432 lang
== nsAXPCNativeCallContext::LANG_JS
) {
440 // XXX this means we are not going to get error reports on non DOM contexts
441 nsIScriptContext
*context
= nsJSUtils::GetDynamicScriptContext(cx
);
443 // Note: we must do this before running any more code on cx (if cx is the
444 // dynamic script context).
445 ::JS_ClearPendingException(cx
);
448 nsIScriptGlobalObject
*globalObject
= context
->GetGlobalObject();
451 nsAutoString fileName
, msg
;
452 if (!report
->filename
) {
453 fileName
.SetIsVoid(PR_TRUE
);
455 fileName
.AssignWithConversion(report
->filename
);
458 const PRUnichar
*m
= reinterpret_cast<const PRUnichar
*>
464 if (msg
.IsEmpty() && message
) {
465 msg
.AssignWithConversion(message
);
469 /* We do not try to report Out Of Memory via a dom
470 * event because the dom event handler would encounter
471 * an OOM exception trying to process the event, and
472 * then we'd need to generate a new OOM event for that
473 * new OOM instance -- this isn't pretty.
475 nsAutoString sourceLine
;
476 sourceLine
.Assign(reinterpret_cast<const PRUnichar
*>(report
->uclinebuf
));
477 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(globalObject
);
478 PRUint64 windowID
= win
? win
->WindowID() : 0;
479 nsContentUtils::AddScriptRunner(
480 new ScriptErrorEvent(globalObject
, report
->lineno
,
481 report
->uctokenptr
- report
->uclinebuf
,
482 report
->flags
, msg
, fileName
, sourceLine
,
483 report
->errorNumber
!= JSMSG_OUT_OF_MEMORY
,
489 // Print it to stderr as well, for the benefit of those invoking
490 // mozilla with -console.
492 error
.Assign("JavaScript ");
493 if (JSREPORT_IS_STRICT(report
->flags
))
494 error
.Append("strict ");
495 if (JSREPORT_IS_WARNING(report
->flags
))
496 error
.Append("warning: ");
498 error
.Append("error: ");
499 error
.Append(report
->filename
);
500 error
.Append(", line ");
501 error
.AppendInt(report
->lineno
, 10);
503 if (report
->ucmessage
) {
504 AppendUTF16toUTF8(reinterpret_cast<const PRUnichar
*>(report
->ucmessage
),
507 error
.Append(message
);
510 fprintf(stderr
, "%s\n", error
.get());
516 gJSDiagnostics
= PR_NewLogModule("JSDiagnostics");
518 if (gJSDiagnostics
) {
519 PR_LOG(gJSDiagnostics
,
520 JSREPORT_IS_WARNING(report
->flags
) ? PR_LOG_WARNING
: PR_LOG_ERROR
,
521 ("file %s, line %u: %s\n%s%s",
522 report
->filename
, report
->lineno
, message
,
523 report
->linebuf
? report
->linebuf
: "",
525 report
->linebuf
[strlen(report
->linebuf
)-1] != '\n')
533 // A couple of useful functions to call when you're debugging.
535 JSObject2Win(JSContext
*cx
, JSObject
*obj
)
537 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
542 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
543 xpc
->GetWrappedNativeOfJSObject(cx
, obj
, getter_AddRefs(wrapper
));
545 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryWrappedNative(wrapper
);
547 return static_cast<nsGlobalWindow
*>
548 (static_cast<nsPIDOMWindow
*>(win
));
556 PrintWinURI(nsGlobalWindow
*win
)
559 printf("No window passed in.\n");
563 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(win
->GetExtantDocument());
565 printf("No document in the window.\n");
569 nsIURI
*uri
= doc
->GetDocumentURI();
571 printf("Document doesn't have a URI.\n");
577 printf("%s\n", spec
.get());
581 PrintWinCodebase(nsGlobalWindow
*win
)
584 printf("No window passed in.\n");
588 nsIPrincipal
*prin
= win
->GetPrincipal();
590 printf("Window doesn't have principals.\n");
594 nsCOMPtr
<nsIURI
> uri
;
595 prin
->GetURI(getter_AddRefs(uri
));
597 printf("No URI, maybe the system principal.\n");
603 printf("%s\n", spec
.get());
607 DumpString(const nsAString
&str
)
609 printf("%s\n", NS_ConvertUTF16toUTF8(str
).get());
613 static already_AddRefed
<nsIPrompt
>
614 GetPromptFromContext(nsJSContext
* ctx
)
616 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(ctx
->GetGlobalObject()));
617 NS_ENSURE_TRUE(win
, nsnull
);
619 nsIDocShell
*docShell
= win
->GetDocShell();
620 NS_ENSURE_TRUE(docShell
, nsnull
);
622 nsCOMPtr
<nsIInterfaceRequestor
> ireq(do_QueryInterface(docShell
));
623 NS_ENSURE_TRUE(ireq
, nsnull
);
625 // Get the nsIPrompt interface from the docshell
627 ireq
->GetInterface(NS_GET_IID(nsIPrompt
), (void**)&prompt
);
632 nsJSContext::DOMOperationCallback(JSContext
*cx
)
636 // Get the native context
637 nsJSContext
*ctx
= static_cast<nsJSContext
*>(::JS_GetContextPrivate(cx
));
640 // Can happen; see bug 355811
644 // XXX Save the operation callback time so we can restore it after the GC,
645 // because GCing can cause JS to run on our context, causing our
646 // ScriptEvaluated to be called, and clearing our operation callback time.
648 PRTime callbackTime
= ctx
->mOperationCallbackTime
;
649 PRTime modalStateTime
= ctx
->mModalStateTime
;
651 // Now restore the callback time and count, in case they got reset.
652 ctx
->mOperationCallbackTime
= callbackTime
;
653 ctx
->mModalStateTime
= modalStateTime
;
655 PRTime now
= PR_Now();
657 if (callbackTime
== 0) {
658 // Initialize mOperationCallbackTime to start timing how long the
660 ctx
->mOperationCallbackTime
= now
;
664 if (ctx
->mModalStateDepth
) {
665 // We're waiting on a modal dialog, nothing more to do here.
669 PRTime duration
= now
- callbackTime
;
671 // Check the amount of time this script has been running, or if the
672 // dialog is disabled.
673 JSObject
* global
= ::JS_GetGlobalForScopeChain(cx
);
674 PRBool isTrackingChromeCodeTime
=
675 global
&& xpc::AccessCheck::isChrome(global
->getCompartment());
676 if (duration
< (isTrackingChromeCodeTime
?
677 sMaxChromeScriptRunTime
: sMaxScriptRunTime
)) {
681 if (!nsContentUtils::IsSafeToRunScript()) {
682 // If it isn't safe to run script, then it isn't safe to bring up the
683 // prompt (since that will cause the event loop to spin). In this case
684 // (which is rare), we just stop the script... But report a warning so
685 // that developers have some idea of what went wrong.
687 JS_ReportWarning(cx
, "A long running script was terminated");
691 // If we get here we're most likely executing an infinite loop in JS,
692 // we'll tell the user about this and we'll give the user the option
693 // of stopping the execution of the script.
694 nsCOMPtr
<nsIPrompt
> prompt
= GetPromptFromContext(ctx
);
695 NS_ENSURE_TRUE(prompt
, JS_TRUE
);
697 // Check if we should offer the option to debug
698 JSStackFrame
* fp
= ::JS_GetScriptedCaller(cx
, NULL
);
699 PRBool debugPossible
= (fp
!= nsnull
&& cx
->debugHooks
&&
700 cx
->debugHooks
->debuggerHandler
!= nsnull
);
701 #ifdef MOZ_JSDEBUGGER
702 // Get the debugger service if necessary.
704 PRBool jsds_IsOn
= PR_FALSE
;
705 const char jsdServiceCtrID
[] = "@mozilla.org/js/jsd/debugger-service;1";
706 nsCOMPtr
<jsdIExecutionHook
> jsdHook
;
707 nsCOMPtr
<jsdIDebuggerService
> jsds
= do_GetService(jsdServiceCtrID
, &rv
);
709 // Check if there's a user for the debugger service that's 'on' for us
710 if (NS_SUCCEEDED(rv
)) {
711 jsds
->GetDebuggerHook(getter_AddRefs(jsdHook
));
712 jsds
->GetIsOn(&jsds_IsOn
);
715 // If there is a debug handler registered for this runtime AND
716 // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
717 // then something useful will be done with our request to debug.
718 debugPossible
= ((jsds_IsOn
&& (jsdHook
!= nsnull
)) || !jsds_IsOn
);
722 // Get localizable strings
723 nsXPIDLString title
, msg
, stopButton
, waitButton
, debugButton
, neverShowDlg
;
725 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
729 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
733 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
734 "WaitForScriptButton",
737 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
743 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
747 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
748 "KillScriptWithDebugMessage",
752 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
757 //GetStringFromName can return NS_OK and still give NULL string
758 if (NS_FAILED(rv
) || !title
|| !msg
|| !stopButton
|| !waitButton
||
759 (!debugButton
&& debugPossible
) || !neverShowDlg
) {
760 NS_ERROR("Failed to get localized strings.");
764 // Append file and line number information, if available
765 JSScript
*script
= fp
? ::JS_GetFrameScript(cx
, fp
) : nsnull
;
767 const char *filename
= ::JS_GetScriptFilename(cx
, script
);
769 nsXPIDLString scriptLocation
;
770 NS_ConvertUTF8toUTF16
filenameUTF16(filename
);
771 const PRUnichar
*formatParams
[] = { filenameUTF16
.get() };
772 rv
= nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
773 "KillScriptLocation",
777 if (NS_SUCCEEDED(rv
) && scriptLocation
) {
778 msg
.AppendLiteral("\n\n");
779 msg
.Append(scriptLocation
);
781 JSStackFrame
*fp
, *iterator
= nsnull
;
782 fp
= ::JS_FrameIterator(cx
, &iterator
);
784 jsbytecode
*pc
= ::JS_GetFramePC(cx
, fp
);
786 PRUint32 lineno
= ::JS_PCToLineNumber(cx
, script
, pc
);
788 msg
.AppendInt(lineno
);
795 PRInt32 buttonPressed
= 0; //In case user exits dialog by clicking X
796 PRBool neverShowDlgChk
= PR_FALSE
;
797 PRUint32 buttonFlags
= nsIPrompt::BUTTON_POS_1_DEFAULT
+
798 (nsIPrompt::BUTTON_TITLE_IS_STRING
*
799 (nsIPrompt::BUTTON_POS_0
+ nsIPrompt::BUTTON_POS_1
));
801 // Add a third button if necessary:
803 buttonFlags
+= nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_2
;
805 // Null out the operation callback while we're re-entering JS here.
806 ::JS_SetOperationCallback(cx
, nsnull
);
809 rv
= prompt
->ConfirmEx(title
, msg
, buttonFlags
, waitButton
, stopButton
,
810 debugButton
, neverShowDlg
, &neverShowDlgChk
,
813 ::JS_SetOperationCallback(cx
, DOMOperationCallback
);
815 if (NS_FAILED(rv
) || (buttonPressed
== 0)) {
816 // Allow the script to continue running
818 if (neverShowDlgChk
) {
819 nsIPrefBranch
*prefBranch
= nsContentUtils::GetPrefBranch();
822 prefBranch
->SetIntPref(isTrackingChromeCodeTime
?
823 "dom.max_chrome_script_run_time" :
824 "dom.max_script_run_time", 0);
828 ctx
->mOperationCallbackTime
= PR_Now();
831 else if ((buttonPressed
== 2) && debugPossible
) {
834 switch(cx
->debugHooks
->debuggerHandler(cx
, script
, ::JS_GetFramePC(cx
, fp
),
837 debuggerHandlerData
)) {
839 JS_SetFrameReturnValue(cx
, fp
, rval
);
842 JS_ClearPendingException(cx
);
845 JS_SetPendingException(cx
, rval
);
847 case JSTRAP_CONTINUE
:
853 JS_ClearPendingException(cx
);
858 nsJSContext::EnterModalState()
860 if (!mModalStateDepth
) {
861 mModalStateTime
= mOperationCallbackTime
? PR_Now() : 0;
867 nsJSContext::LeaveModalState()
869 if (!mModalStateDepth
) {
870 NS_ERROR("Uh, mismatched LeaveModalState() call!");
877 // If we're still in a modal dialog, or mOperationCallbackTime is still
878 // uninitialized, do nothing.
879 if (mModalStateDepth
|| !mOperationCallbackTime
) {
883 // If mOperationCallbackTime was set when we entered the first dialog
884 // (and mModalStateTime is thus non-zero), adjust mOperationCallbackTime
885 // to account for time spent in the dialog.
886 // If mOperationCallbackTime got set while the modal dialog was open,
887 // simply set mOperationCallbackTime to the closing time of the dialog so
888 // that we never adjust mOperationCallbackTime to be in the future.
889 if (mModalStateTime
) {
890 mOperationCallbackTime
+= PR_Now() - mModalStateTime
;
893 mOperationCallbackTime
= PR_Now();
897 #define JS_OPTIONS_DOT_STR "javascript.options."
899 static const char js_options_dot_str
[] = JS_OPTIONS_DOT_STR
;
900 static const char js_strict_option_str
[] = JS_OPTIONS_DOT_STR
"strict";
902 static const char js_strict_debug_option_str
[] = JS_OPTIONS_DOT_STR
"strict.debug";
904 static const char js_werror_option_str
[] = JS_OPTIONS_DOT_STR
"werror";
905 static const char js_relimit_option_str
[]= JS_OPTIONS_DOT_STR
"relimit";
907 static const char js_zeal_option_str
[] = JS_OPTIONS_DOT_STR
"gczeal";
909 static const char js_tracejit_content_str
[] = JS_OPTIONS_DOT_STR
"tracejit.content";
910 static const char js_tracejit_chrome_str
[] = JS_OPTIONS_DOT_STR
"tracejit.chrome";
911 static const char js_methodjit_content_str
[] = JS_OPTIONS_DOT_STR
"methodjit.content";
912 static const char js_methodjit_chrome_str
[] = JS_OPTIONS_DOT_STR
"methodjit.chrome";
913 static const char js_profiling_content_str
[] = JS_OPTIONS_DOT_STR
"jitprofiling.content";
914 static const char js_profiling_chrome_str
[] = JS_OPTIONS_DOT_STR
"jitprofiling.chrome";
915 static const char js_methodjit_always_str
[] = JS_OPTIONS_DOT_STR
"methodjit_always";
916 static const char js_memlog_option_str
[] = JS_OPTIONS_DOT_STR
"mem.log";
919 nsJSContext::JSOptionChangedCallback(const char *pref
, void *data
)
921 nsJSContext
*context
= reinterpret_cast<nsJSContext
*>(data
);
922 PRUint32 oldDefaultJSOptions
= context
->mDefaultJSOptions
;
923 PRUint32 newDefaultJSOptions
= oldDefaultJSOptions
;
925 sPostGCEventsToConsole
= nsContentUtils::GetBoolPref(js_memlog_option_str
);
927 PRBool strict
= nsContentUtils::GetBoolPref(js_strict_option_str
);
929 newDefaultJSOptions
|= JSOPTION_STRICT
;
931 newDefaultJSOptions
&= ~JSOPTION_STRICT
;
933 nsIScriptGlobalObject
*global
= context
->GetGlobalObject();
934 // XXX should we check for sysprin instead of a chrome window, to make
935 // XXX components be covered by the chrome pref instead of the content one?
936 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(global
));
938 PRBool useTraceJIT
= nsContentUtils::GetBoolPref(chromeWindow
?
939 js_tracejit_chrome_str
:
940 js_tracejit_content_str
);
941 PRBool useMethodJIT
= nsContentUtils::GetBoolPref(chromeWindow
?
942 js_methodjit_chrome_str
:
943 js_methodjit_content_str
);
944 PRBool useProfiling
= nsContentUtils::GetBoolPref(chromeWindow
?
945 js_profiling_chrome_str
:
946 js_profiling_content_str
);
947 PRBool useMethodJITAlways
= nsContentUtils::GetBoolPref(js_methodjit_always_str
);
948 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService(XULRUNTIME_SERVICE_CONTRACTID
);
950 PRBool safeMode
= PR_FALSE
;
951 xr
->GetInSafeMode(&safeMode
);
953 useTraceJIT
= PR_FALSE
;
954 useMethodJIT
= PR_FALSE
;
955 useProfiling
= PR_FALSE
;
956 useMethodJITAlways
= PR_TRUE
;
961 newDefaultJSOptions
|= JSOPTION_JIT
;
963 newDefaultJSOptions
&= ~JSOPTION_JIT
;
966 newDefaultJSOptions
|= JSOPTION_METHODJIT
;
968 newDefaultJSOptions
&= ~JSOPTION_METHODJIT
;
971 newDefaultJSOptions
|= JSOPTION_PROFILING
;
973 newDefaultJSOptions
&= ~JSOPTION_PROFILING
;
975 if (useMethodJITAlways
)
976 newDefaultJSOptions
|= JSOPTION_METHODJIT_ALWAYS
;
978 newDefaultJSOptions
&= ~JSOPTION_METHODJIT_ALWAYS
;
981 // In debug builds, warnings are enabled in chrome context if
982 // javascript.options.strict.debug is true
983 PRBool strictDebug
= nsContentUtils::GetBoolPref(js_strict_debug_option_str
);
984 // Note this callback is also called from context's InitClasses thus we don't
985 // need to enable this directly from InitContext
986 if (strictDebug
&& (newDefaultJSOptions
& JSOPTION_STRICT
) == 0) {
988 newDefaultJSOptions
|= JSOPTION_STRICT
;
992 PRBool werror
= nsContentUtils::GetBoolPref(js_werror_option_str
);
994 newDefaultJSOptions
|= JSOPTION_WERROR
;
996 newDefaultJSOptions
&= ~JSOPTION_WERROR
;
998 PRBool relimit
= nsContentUtils::GetBoolPref(js_relimit_option_str
);
1000 newDefaultJSOptions
|= JSOPTION_RELIMIT
;
1002 newDefaultJSOptions
&= ~JSOPTION_RELIMIT
;
1004 ::JS_SetOptions(context
->mContext
, newDefaultJSOptions
& JSRUNOPTION_MASK
);
1006 // Save the new defaults for the next page load (InitContext).
1007 context
->mDefaultJSOptions
= newDefaultJSOptions
;
1010 PRInt32 zeal
= nsContentUtils::GetIntPref(js_zeal_option_str
, -1);
1012 ::JS_SetGCZeal(context
->mContext
, (PRUint8
)zeal
);
1018 nsJSContext::nsJSContext(JSRuntime
*aRuntime
)
1019 : mGCOnDestruction(PR_TRUE
),
1025 mDefaultJSOptions
= JSOPTION_PRIVATE_IS_NSISUPPORTS
| JSOPTION_ANONFUNFIX
;
1027 mContext
= ::JS_NewContext(aRuntime
, gStackSize
);
1029 ::JS_SetContextPrivate(mContext
, static_cast<nsIScriptContext
*>(this));
1031 // Preserve any flags the context callback might have set.
1032 mDefaultJSOptions
|= ::JS_GetOptions(mContext
);
1034 // Make sure the new context gets the default context options
1035 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
1037 // Watch for the JS boolean options
1038 nsContentUtils::RegisterPrefCallback(js_options_dot_str
,
1039 JSOptionChangedCallback
,
1042 ::JS_SetOperationCallback(mContext
, DOMOperationCallback
);
1044 xpc_LocalizeContext(mContext
);
1046 mIsInitialized
= PR_FALSE
;
1047 mTerminations
= nsnull
;
1048 mScriptsEnabled
= PR_TRUE
;
1049 mOperationCallbackTime
= 0;
1050 mModalStateTime
= 0;
1051 mModalStateDepth
= 0;
1052 mProcessingScriptTag
= PR_FALSE
;
1055 nsJSContext::~nsJSContext()
1058 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptContext
*>(this));
1061 // We may still have pending termination functions if the context is destroyed
1062 // before they could be executed. In this case, free the references to their
1063 // parameters, but don't execute the functions (see bug 622326).
1064 delete mTerminations
;
1066 mGlobalObjectRef
= nsnull
;
1072 if (!sContextCount
&& sDidShutdown
) {
1073 // The last context is being deleted, and we're already in the
1074 // process of shutting down, release the JS runtime service, and
1075 // the security manager.
1077 NS_IF_RELEASE(sRuntimeService
);
1078 NS_IF_RELEASE(sSecurityManager
);
1083 nsJSContext::DestroyJSContext()
1088 // Clear our entry in the JSContext, bugzilla bug 66413
1089 ::JS_SetContextPrivate(mContext
, nsnull
);
1091 // Unregister our "javascript.options.*" pref-changed callback.
1092 nsContentUtils::UnregisterPrefCallback(js_options_dot_str
,
1093 JSOptionChangedCallback
,
1096 PRBool do_gc
= mGCOnDestruction
&& !sGCTimer
;
1098 // Let xpconnect destroy the JSContext when it thinks the time is right.
1099 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
1101 xpc
->ReleaseJSContext(mContext
, !do_gc
);
1103 ::JS_DestroyContext(mContext
);
1105 ::JS_DestroyContextNoGC(mContext
);
1110 // QueryInterface implementation for nsJSContext
1111 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext
)
1112 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSContext
)
1113 NS_ASSERTION(!tmp
->mContext
|| tmp
->mContext
->outstandingRequests
== 0,
1114 "Trying to unlink a context with outstanding requests.");
1115 tmp
->mIsInitialized
= PR_FALSE
;
1116 tmp
->mGCOnDestruction
= PR_FALSE
;
1117 tmp
->DestroyJSContext();
1118 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1119 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext
)
1120 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1121 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext
)
1122 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObjectRef
)
1123 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1124 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext
)
1125 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext
, tmp
->GetCCRefcnt())
1126 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalObjectRef
)
1127 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mContext");
1128 nsContentUtils::XPConnect()->NoteJSContext(tmp
->mContext
, cb
);
1129 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1131 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext
)
1132 NS_INTERFACE_MAP_ENTRY(nsIScriptContext
)
1133 NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal
)
1134 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify
)
1135 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIScriptContext
)
1136 NS_INTERFACE_MAP_END
1139 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSContext
, nsIScriptContext
)
1140 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSContext
, nsIScriptContext
)
1143 nsJSContext::GetCCRefcnt()
1145 nsrefcnt refcnt
= mRefCnt
.get();
1146 if (NS_LIKELY(mContext
))
1147 refcnt
+= mContext
->outstandingRequests
;
1152 nsJSContext::EvaluateStringWithValue(const nsAString
& aScript
,
1154 nsIPrincipal
*aPrincipal
,
1159 PRBool
* aIsUndefined
)
1161 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1162 __LINE__
, aURL
, aLineNo
);
1164 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1166 if (!mScriptsEnabled
) {
1168 *aIsUndefined
= PR_TRUE
;
1176 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1178 // Safety first: get an object representing the script's principals, i.e.,
1179 // the entities who signed this script, or the fully-qualified-domain-name
1180 // or "codebase" from which it was loaded.
1181 JSPrincipals
*jsprin
;
1182 nsIPrincipal
*principal
= aPrincipal
;
1184 nsIScriptGlobalObject
*global
= GetGlobalObject();
1186 return NS_ERROR_FAILURE
;
1187 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
1188 do_QueryInterface(global
, &rv
);
1190 return NS_ERROR_FAILURE
;
1191 principal
= objPrincipal
->GetPrincipal();
1193 return NS_ERROR_FAILURE
;
1196 principal
->GetJSPrincipals(mContext
, &jsprin
);
1198 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1200 PRBool ok
= PR_FALSE
;
1202 rv
= sSecurityManager
->CanExecuteScripts(mContext
, principal
, &ok
);
1203 if (NS_FAILED(rv
)) {
1204 JSPRINCIPALS_DROP(mContext
, jsprin
);
1205 return NS_ERROR_FAILURE
;
1208 // Push our JSContext on the current thread's context stack so JS called
1209 // from native code via XPConnect uses the right context. Do this whether
1210 // or not the SecurityManager said "ok", in order to simplify control flow
1211 // below where we pop before returning.
1212 nsCOMPtr
<nsIJSContextStack
> stack
=
1213 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1214 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1215 JSPRINCIPALS_DROP(mContext
, jsprin
);
1216 return NS_ERROR_FAILURE
;
1221 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1222 NS_ENSURE_SUCCESS(rv
, rv
);
1224 nsJSContext::TerminationFuncHolder
holder(this);
1226 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1227 // Since the caller is responsible for parsing the version strings, we just
1228 // check it isn't JSVERSION_UNKNOWN.
1229 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1231 JSAutoRequest
ar(mContext
);
1233 JSAutoEnterCompartment ac
;
1234 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1235 JSPRINCIPALS_DROP(mContext
, jsprin
);
1237 return NS_ERROR_FAILURE
;
1242 ok
= ::JS_EvaluateUCScriptForPrincipalsVersion(mContext
,
1243 (JSObject
*)aScopeObject
,
1245 (jschar
*)PromiseFlatString(aScript
).get(),
1250 JSVersion(aVersion
));
1255 // Tell XPConnect about any pending exceptions. This is needed
1256 // to avoid dropping JS exceptions in case we got here through
1257 // nested calls through XPConnect.
1259 ReportPendingException();
1263 // Whew! Finally done with these manually ref-counted things.
1264 JSPRINCIPALS_DROP(mContext
, jsprin
);
1266 // If all went well, convert val to a string (XXXbe unless undefined?).
1269 *aIsUndefined
= JSVAL_IS_VOID(val
);
1272 *static_cast<jsval
*>(aRetValue
) = val
;
1273 // XXX - nsScriptObjectHolder should be used once this method moves to
1274 // the new world order. However, use of 'jsval' appears to make this
1279 *aIsUndefined
= PR_TRUE
;
1283 sSecurityManager
->PopContextPrincipal(mContext
);
1285 // Pop here, after JS_ValueToString and any other possible evaluation.
1286 if (NS_FAILED(stack
->Pop(nsnull
)))
1287 rv
= NS_ERROR_FAILURE
;
1289 // ScriptEvaluated needs to come after we pop the stack
1290 ScriptEvaluated(PR_TRUE
);
1296 // Helper function to convert a jsval to an nsAString, and set
1297 // exception flags if the conversion fails.
1299 JSValueToAString(JSContext
*cx
, jsval val
, nsAString
*result
,
1300 PRBool
*isUndefined
)
1303 *isUndefined
= JSVAL_IS_VOID(val
);
1310 JSString
* jsstring
= ::JS_ValueToString(cx
, val
);
1316 const jschar
*chars
;
1317 chars
= ::JS_GetStringCharsAndLength(cx
, jsstring
, &length
);
1322 result
->Assign(chars
, length
);
1326 // We failed to convert val to a string. We're either OOM, or the
1327 // security manager denied access to .toString(), or somesuch, on
1328 // an object. Treat this case as if the result were undefined.
1333 *isUndefined
= PR_TRUE
;
1336 if (!::JS_IsExceptionPending(cx
)) {
1337 // JS_ValueToString()/JS_GetStringCharsAndLength returned null w/o an
1338 // exception pending. That means we're OOM.
1340 return NS_ERROR_OUT_OF_MEMORY
;
1346 nsIScriptObjectPrincipal
*
1347 nsJSContext::GetObjectPrincipal()
1349 nsCOMPtr
<nsIScriptObjectPrincipal
> prin
= do_QueryInterface(GetGlobalObject());
1354 nsJSContext::EvaluateString(const nsAString
& aScript
,
1356 nsIPrincipal
*aPrincipal
,
1360 nsAString
*aRetValue
,
1361 PRBool
* aIsUndefined
)
1363 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1364 __LINE__
, aURL
, aLineNo
);
1366 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1368 if (!mScriptsEnabled
) {
1370 *aIsUndefined
= PR_TRUE
;
1374 aRetValue
->Truncate();
1382 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1384 // Safety first: get an object representing the script's principals, i.e.,
1385 // the entities who signed this script, or the fully-qualified-domain-name
1386 // or "codebase" from which it was loaded.
1387 JSPrincipals
*jsprin
;
1388 nsIPrincipal
*principal
= aPrincipal
;
1390 aPrincipal
->GetJSPrincipals(mContext
, &jsprin
);
1393 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
1394 do_QueryInterface(GetGlobalObject(), &rv
);
1396 return NS_ERROR_FAILURE
;
1397 principal
= objPrincipal
->GetPrincipal();
1399 return NS_ERROR_FAILURE
;
1400 principal
->GetJSPrincipals(mContext
, &jsprin
);
1403 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1405 PRBool ok
= PR_FALSE
;
1407 rv
= sSecurityManager
->CanExecuteScripts(mContext
, principal
, &ok
);
1408 if (NS_FAILED(rv
)) {
1409 JSPRINCIPALS_DROP(mContext
, jsprin
);
1410 return NS_ERROR_FAILURE
;
1413 // Push our JSContext on the current thread's context stack so JS called
1414 // from native code via XPConnect uses the right context. Do this whether
1415 // or not the SecurityManager said "ok", in order to simplify control flow
1416 // below where we pop before returning.
1417 nsCOMPtr
<nsIJSContextStack
> stack
=
1418 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1419 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1420 JSPRINCIPALS_DROP(mContext
, jsprin
);
1421 return NS_ERROR_FAILURE
;
1424 // The result of evaluation, used only if there were no errors. This need
1425 // not be a GC root currently, provided we run the GC only from the
1426 // operation callback or from ScriptEvaluated.
1427 jsval val
= JSVAL_VOID
;
1428 jsval
* vp
= aRetValue
? &val
: NULL
;
1430 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1431 NS_ENSURE_SUCCESS(rv
, rv
);
1433 nsJSContext::TerminationFuncHolder
holder(this);
1437 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1438 // Since the caller is responsible for parsing the version strings, we just
1439 // check it isn't JSVERSION_UNKNOWN.
1440 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1441 JSAutoRequest
ar(mContext
);
1442 JSAutoEnterCompartment ac
;
1443 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1445 JSPRINCIPALS_DROP(mContext
, jsprin
);
1446 return NS_ERROR_FAILURE
;
1449 ok
= ::JS_EvaluateUCScriptForPrincipalsVersion(mContext
,
1450 (JSObject
*)aScopeObject
,
1452 (jschar
*)PromiseFlatString(aScript
).get(),
1457 JSVersion(aVersion
));
1460 // Tell XPConnect about any pending exceptions. This is needed
1461 // to avoid dropping JS exceptions in case we got here through
1462 // nested calls through XPConnect.
1464 ReportPendingException();
1468 // Whew! Finally done with these manually ref-counted things.
1469 JSPRINCIPALS_DROP(mContext
, jsprin
);
1471 // If all went well, convert val to a string if one is wanted.
1473 JSAutoRequest
ar(mContext
);
1474 JSAutoEnterCompartment ac
;
1475 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1478 rv
= JSValueToAString(mContext
, val
, aRetValue
, aIsUndefined
);
1482 *aIsUndefined
= PR_TRUE
;
1486 aRetValue
->Truncate();
1492 sSecurityManager
->PopContextPrincipal(mContext
);
1494 // Pop here, after JS_ValueToString and any other possible evaluation.
1495 if (NS_FAILED(stack
->Pop(nsnull
)))
1496 rv
= NS_ERROR_FAILURE
;
1498 // ScriptEvaluated needs to come after we pop the stack
1499 ScriptEvaluated(PR_TRUE
);
1505 nsJSContext::CompileScript(const PRUnichar
* aText
,
1506 PRInt32 aTextLength
,
1508 nsIPrincipal
*aPrincipal
,
1512 nsScriptObjectHolder
&aScriptObject
)
1514 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1517 NS_ENSURE_ARG_POINTER(aPrincipal
);
1520 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1522 JSPrincipals
*jsprin
;
1523 aPrincipal
->GetJSPrincipals(mContext
, &jsprin
);
1524 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1526 PRBool ok
= PR_FALSE
;
1528 rv
= sSecurityManager
->CanExecuteScripts(mContext
, aPrincipal
, &ok
);
1529 if (NS_FAILED(rv
)) {
1530 JSPRINCIPALS_DROP(mContext
, jsprin
);
1531 return NS_ERROR_FAILURE
;
1534 aScriptObject
.drop(); // ensure old object not used on failure...
1536 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1537 // Since the caller is responsible for parsing the version strings, we just
1538 // check it isn't JSVERSION_UNKNOWN.
1539 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1540 JSAutoRequest
ar(mContext
);
1543 ::JS_CompileUCScriptForPrincipalsVersion(mContext
,
1544 (JSObject
*)aScopeObject
,
1550 JSVersion(aVersion
));
1552 JSObject
*scriptObject
= ::JS_NewScriptObject(mContext
, script
);
1554 NS_ASSERTION(aScriptObject
.getScriptTypeID()==JAVASCRIPT
,
1555 "Expecting JS script object holder");
1556 rv
= aScriptObject
.set(scriptObject
);
1558 ::JS_DestroyScript(mContext
, script
);
1562 rv
= NS_ERROR_OUT_OF_MEMORY
;
1566 // Whew! Finally done.
1567 JSPRINCIPALS_DROP(mContext
, jsprin
);
1572 nsJSContext::ExecuteScript(void *aScriptObject
,
1574 nsAString
* aRetValue
,
1575 PRBool
* aIsUndefined
)
1577 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1579 if (!mScriptsEnabled
) {
1581 *aIsUndefined
= PR_TRUE
;
1585 aRetValue
->Truncate();
1594 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1596 // Push our JSContext on our thread's context stack, in case native code
1597 // called from JS calls back into JS via XPConnect.
1598 nsCOMPtr
<nsIJSContextStack
> stack
=
1599 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1600 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1601 return NS_ERROR_FAILURE
;
1604 // The result of evaluation, used only if there were no errors. This need
1605 // not be a GC root currently, provided we run the GC only from the
1606 // operation callback or from ScriptEvaluated.
1610 JSObject
*scriptObj
= (JSObject
*)aScriptObject
;
1611 nsCOMPtr
<nsIPrincipal
> principal
;
1613 rv
= sSecurityManager
->GetObjectPrincipal(mContext
, scriptObj
, getter_AddRefs(principal
));
1614 NS_ENSURE_SUCCESS(rv
, rv
);
1616 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1617 NS_ENSURE_SUCCESS(rv
, rv
);
1619 nsJSContext::TerminationFuncHolder
holder(this);
1620 JSAutoRequest
ar(mContext
);
1622 ok
= ::JS_ExecuteScript(mContext
,
1623 (JSObject
*)aScopeObject
,
1624 (JSScript
*)::JS_GetPrivate(mContext
, scriptObj
),
1628 // If all went well, convert val to a string (XXXbe unless undefined?).
1629 rv
= JSValueToAString(mContext
, val
, aRetValue
, aIsUndefined
);
1632 *aIsUndefined
= PR_TRUE
;
1636 aRetValue
->Truncate();
1642 sSecurityManager
->PopContextPrincipal(mContext
);
1644 // Pop here, after JS_ValueToString and any other possible evaluation.
1645 if (NS_FAILED(stack
->Pop(nsnull
)))
1646 rv
= NS_ERROR_FAILURE
;
1648 // ScriptEvaluated needs to come after we pop the stack
1649 ScriptEvaluated(PR_TRUE
);
1657 AtomIsEventHandlerName(nsIAtom
*aName
)
1659 const PRUnichar
*name
= aName
->GetUTF16String();
1661 const PRUnichar
*cp
;
1663 for (cp
= name
; *cp
!= '\0'; ++cp
)
1666 if ((c
< 'A' || c
> 'Z') && (c
< 'a' || c
> 'z'))
1674 // Helper function to find the JSObject associated with a (presumably DOM)
1677 nsJSContext::JSObjectFromInterface(nsISupports
* aTarget
, void *aScope
, JSObject
**aRet
)
1679 // It is legal to specify a null target.
1685 // Get the jsobject associated with this target
1686 // We don't wrap here because we trust the JS engine to wrap the target
1690 rv
= nsContentUtils::WrapNative(mContext
, (JSObject
*)aScope
, aTarget
, &v
);
1691 NS_ENSURE_SUCCESS(rv
, rv
);
1694 nsCOMPtr
<nsISupports
> targetSupp
= do_QueryInterface(aTarget
);
1695 nsCOMPtr
<nsISupports
> native
=
1696 nsContentUtils::XPConnect()->GetNativeOfWrapper(mContext
,
1697 JSVAL_TO_OBJECT(v
));
1698 NS_ASSERTION(native
== targetSupp
, "Native should be the target!");
1701 *aRet
= JSVAL_TO_OBJECT(v
);
1708 nsJSContext::CompileEventHandler(nsIAtom
*aName
,
1710 const char** aArgNames
,
1711 const nsAString
& aBody
,
1712 const char *aURL
, PRUint32 aLineNo
,
1714 nsScriptObjectHolder
&aHandler
)
1716 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1717 __LINE__
, aURL
, aLineNo
);
1719 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1721 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
1722 NS_PRECONDITION(!::JS_IsExceptionPending(mContext
),
1723 "Why are we being called with a pending exception?");
1725 if (!sSecurityManager
) {
1726 NS_ERROR("Huh, we need a script security manager to compile "
1727 "an event handler!");
1729 return NS_ERROR_UNEXPECTED
;
1732 // Don't compile if aVersion is unknown. Since the caller is responsible for
1733 // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
1734 if ((JSVersion
)aVersion
== JSVERSION_UNKNOWN
) {
1735 return NS_ERROR_ILLEGAL_VALUE
;
1739 JSContext
* top
= nsContentUtils::GetCurrentJSContext();
1740 NS_ASSERTION(mContext
== top
, "Context not properly pushed!");
1743 // Event handlers are always shared, and must be bound before use.
1744 // Therefore we never bother compiling with principals.
1745 // (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
1746 JSAutoRequest
ar(mContext
);
1749 ::JS_CompileUCFunctionForPrincipalsVersion(mContext
,
1751 nsAtomCString(aName
).get(), aArgCount
, aArgNames
,
1752 (jschar
*)PromiseFlatString(aBody
).get(),
1754 aURL
, aLineNo
, JSVersion(aVersion
));
1757 ReportPendingException();
1758 return NS_ERROR_ILLEGAL_VALUE
;
1761 JSObject
*handler
= ::JS_GetFunctionObject(fun
);
1762 NS_ASSERTION(aHandler
.getScriptTypeID()==JAVASCRIPT
,
1763 "Expecting JS script object holder");
1764 return aHandler
.set((void *)handler
);
1767 // XXX - note that CompileFunction doesn't yet play the nsScriptObjectHolder
1768 // game - caller must still ensure JS GC root.
1770 nsJSContext::CompileFunction(void* aTarget
,
1771 const nsACString
& aName
,
1773 const char** aArgArray
,
1774 const nsAString
& aBody
,
1779 void** aFunctionObject
)
1781 NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s, url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1782 __LINE__
, aName
.BeginReading(), aURL
, aLineNo
);
1784 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1786 // Don't compile if aVersion is unknown. Since the caller is responsible for
1787 // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
1788 if ((JSVersion
)aVersion
== JSVERSION_UNKNOWN
) {
1789 return NS_ERROR_ILLEGAL_VALUE
;
1792 JSPrincipals
*jsprin
= nsnull
;
1794 nsIScriptGlobalObject
*global
= GetGlobalObject();
1796 // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
1797 nsCOMPtr
<nsIScriptObjectPrincipal
> globalData
= do_QueryInterface(global
);
1799 nsIPrincipal
*prin
= globalData
->GetPrincipal();
1801 return NS_ERROR_FAILURE
;
1802 prin
->GetJSPrincipals(mContext
, &jsprin
);
1806 JSObject
*target
= (JSObject
*)aTarget
;
1808 JSAutoRequest
ar(mContext
);
1811 ::JS_CompileUCFunctionForPrincipalsVersion(mContext
,
1812 aShared
? nsnull
: target
, jsprin
,
1813 PromiseFlatCString(aName
).get(),
1814 aArgCount
, aArgArray
,
1815 (jschar
*)PromiseFlatString(aBody
).get(),
1818 JSVersion(aVersion
));
1821 JSPRINCIPALS_DROP(mContext
, jsprin
);
1823 return NS_ERROR_FAILURE
;
1825 JSObject
*handler
= ::JS_GetFunctionObject(fun
);
1826 if (aFunctionObject
)
1827 *aFunctionObject
= (void*) handler
;
1832 nsJSContext::CallEventHandler(nsISupports
* aTarget
, void *aScope
, void *aHandler
,
1833 nsIArray
*aargv
, nsIVariant
**arv
)
1835 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1837 if (!mScriptsEnabled
) {
1841 #ifdef NS_FUNCTION_TIMER
1843 JSObject
*obj
= static_cast<JSObject
*>(aHandler
);
1844 JSString
*id
= JS_GetFunctionId(static_cast<JSFunction
*>(JS_GetPrivate(mContext
, obj
)));
1845 JSAutoByteString bytes
;
1846 const char *name
= !id
? "anonymous" : bytes
.encode(mContext
, id
) ? bytes
.ptr() : "<error>";
1847 NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME
, __LINE__
, name
);
1851 JSAutoRequest
ar(mContext
);
1852 JSObject
* target
= nsnull
;
1853 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &target
);
1854 NS_ENSURE_SUCCESS(rv
, rv
);
1856 js::AutoObjectRooter
targetVal(mContext
, target
);
1857 jsval rval
= JSVAL_VOID
;
1859 // This one's a lot easier than EvaluateString because we don't have to
1860 // hassle with principals: they're already compiled into the JS function.
1861 // xxxmarkh - this comment is no longer true - principals are not used at
1862 // all now, and never were in some cases.
1865 if (!pusher
.Push(mContext
, PR_TRUE
))
1866 return NS_ERROR_FAILURE
;
1868 // check if the event handler can be run on the object in question
1869 rv
= sSecurityManager
->CheckFunctionAccess(mContext
, aHandler
, target
);
1871 nsJSContext::TerminationFuncHolder
holder(this);
1873 if (NS_SUCCEEDED(rv
)) {
1874 // Convert args to jsvals.
1876 jsval
*argv
= nsnull
;
1878 JSObject
*funobj
= static_cast<JSObject
*>(aHandler
);
1879 nsCOMPtr
<nsIPrincipal
> principal
;
1880 rv
= sSecurityManager
->GetObjectPrincipal(mContext
, funobj
,
1881 getter_AddRefs(principal
));
1882 NS_ENSURE_SUCCESS(rv
, rv
);
1884 JSStackFrame
*currentfp
= nsnull
;
1885 rv
= sSecurityManager
->PushContextPrincipal(mContext
,
1886 JS_FrameIterator(mContext
, ¤tfp
),
1888 NS_ENSURE_SUCCESS(rv
, rv
);
1890 jsval funval
= OBJECT_TO_JSVAL(funobj
);
1891 JSAutoEnterCompartment ac
;
1892 if (!ac
.enter(mContext
, funobj
) || !JS_WrapObject(mContext
, &target
)) {
1893 sSecurityManager
->PopContextPrincipal(mContext
);
1894 return NS_ERROR_FAILURE
;
1897 js::LazilyConstructed
<nsAutoPoolRelease
> poolRelease
;
1898 js::LazilyConstructed
<js::AutoArrayRooter
> tvr
;
1900 // Use |target| as the scope for wrapping the arguments, since aScope is
1901 // the safe scope in many cases, which isn't very useful. Wrapping aTarget
1902 // was OK because those typically have PreCreate methods that give them the
1903 // right scope anyway, and we want to make sure that the arguments end up
1904 // in the same scope as aTarget.
1905 rv
= ConvertSupportsTojsvals(aargv
, target
, &argc
,
1906 &argv
, poolRelease
, tvr
);
1907 NS_ENSURE_SUCCESS(rv
, rv
);
1910 PRBool ok
= ::JS_CallFunctionValue(mContext
, target
,
1911 funval
, argc
, argv
, &rval
);
1915 // Tell XPConnect about any pending exceptions. This is needed
1916 // to avoid dropping JS exceptions in case we got here through
1917 // nested calls through XPConnect.
1919 ReportPendingException();
1921 // Don't pass back results from failed calls.
1924 // Tell the caller that the handler threw an error.
1925 rv
= NS_ERROR_FAILURE
;
1928 sSecurityManager
->PopContextPrincipal(mContext
);
1933 // Convert to variant before calling ScriptEvaluated, as it may GC, meaning
1934 // we would need to root rval.
1935 if (NS_SUCCEEDED(rv
)) {
1936 if (rval
== JSVAL_NULL
)
1939 rv
= nsContentUtils::XPConnect()->JSToVariant(mContext
, rval
, arv
);
1942 // ScriptEvaluated needs to come after we pop the stack
1943 ScriptEvaluated(PR_TRUE
);
1949 nsJSContext::BindCompiledEventHandler(nsISupports
* aTarget
, void *aScope
,
1953 NS_ENSURE_ARG(aHandler
);
1954 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1956 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
1958 JSAutoRequest
ar(mContext
);
1960 // Get the jsobject associated with this target
1961 JSObject
*target
= nsnull
;
1962 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &target
);
1963 NS_ENSURE_SUCCESS(rv
, rv
);
1965 JSObject
*funobj
= (JSObject
*) aHandler
;
1969 JSAutoEnterCompartment ac
;
1970 if (!ac
.enter(mContext
, funobj
)) {
1971 return NS_ERROR_FAILURE
;
1974 NS_ASSERTION(JS_TypeOfValue(mContext
,
1975 OBJECT_TO_JSVAL(funobj
)) == JSTYPE_FUNCTION
,
1976 "Event handler object not a function");
1980 JSAutoEnterCompartment ac
;
1981 if (!ac
.enter(mContext
, target
)) {
1982 return NS_ERROR_FAILURE
;
1985 // Push our JSContext on our thread's context stack, in case native code
1986 // called from JS calls back into JS via XPConnect.
1987 nsCOMPtr
<nsIJSContextStack
> stack
=
1988 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1989 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1990 return NS_ERROR_FAILURE
;
1993 // Make sure the handler function is parented by its event target object
1994 if (funobj
) { // && ::JS_GetParent(mContext, funobj) != target) {
1995 funobj
= ::JS_CloneFunctionObject(mContext
, funobj
, target
);
1997 rv
= NS_ERROR_OUT_OF_MEMORY
;
2000 if (NS_SUCCEEDED(rv
) &&
2001 // Make sure the flags here match those in nsEventReceiverSH::NewResolve
2002 !::JS_DefineProperty(mContext
, target
, nsAtomCString(aName
).get(),
2003 OBJECT_TO_JSVAL(funobj
), nsnull
, nsnull
,
2004 JSPROP_ENUMERATE
| JSPROP_PERMANENT
)) {
2005 ReportPendingException();
2006 rv
= NS_ERROR_FAILURE
;
2009 // XXXmarkh - ideally we should assert that the wrapped native is now
2010 // "long lived" - how to do that?
2012 if (NS_FAILED(stack
->Pop(nsnull
)) && NS_SUCCEEDED(rv
)) {
2013 rv
= NS_ERROR_FAILURE
;
2020 nsJSContext::GetBoundEventHandler(nsISupports
* aTarget
, void *aScope
,
2022 nsScriptObjectHolder
&aHandler
)
2024 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
2026 JSAutoRequest
ar(mContext
);
2027 JSObject
*obj
= nsnull
;
2028 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &obj
);
2029 NS_ENSURE_SUCCESS(rv
, rv
);
2031 JSAutoEnterCompartment ac
;
2032 if (!ac
.enter(mContext
, obj
)) {
2033 return NS_ERROR_FAILURE
;
2037 if (!JS_LookupProperty(mContext
, obj
,
2038 nsAtomCString(aName
).get(), &funval
))
2039 return NS_ERROR_FAILURE
;
2041 if (JS_TypeOfValue(mContext
, funval
) != JSTYPE_FUNCTION
) {
2042 NS_WARNING("Event handler object not a function");
2046 NS_ASSERTION(aHandler
.getScriptTypeID()==JAVASCRIPT
,
2047 "Expecting JS script object holder");
2048 return aHandler
.set(JSVAL_TO_OBJECT(funval
));
2053 nsJSContext::Serialize(nsIObjectOutputStream
* aStream
, void *aScriptObject
)
2055 JSObject
*mJSObject
= (JSObject
*)aScriptObject
;
2057 return NS_ERROR_FAILURE
;
2061 JSContext
* cx
= mContext
;
2062 JSXDRState
*xdr
= ::JS_XDRNewMem(cx
, JSXDR_ENCODE
);
2064 return NS_ERROR_OUT_OF_MEMORY
;
2065 xdr
->userdata
= (void*) aStream
;
2067 JSAutoRequest
ar(cx
);
2068 JSScript
*script
= reinterpret_cast<JSScript
*>
2069 (::JS_GetPrivate(cx
, mJSObject
));
2070 if (! ::JS_XDRScript(xdr
, &script
)) {
2071 rv
= NS_ERROR_FAILURE
; // likely to be a principals serialization error
2073 // Get the encoded JSXDRState data and write it. The JSXDRState owns
2074 // this buffer memory and will free it beneath ::JS_XDRDestroy.
2076 // If an XPCOM object needs to be written in the midst of the JS XDR
2077 // encoding process, the C++ code called back from the JS engine (e.g.,
2078 // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data
2079 // from the JSXDRState to aStream, then write the object, then return
2080 // to JS XDR code with xdr reset so new JS data is encoded at the front
2081 // of the xdr's data buffer.
2083 // However many XPCOM objects are interleaved with JS XDR data in the
2084 // stream, when control returns here from ::JS_XDRScript, we'll have
2085 // one last buffer of data to write to aStream.
2088 const char* data
= reinterpret_cast<const char*>
2089 (::JS_XDRMemGetData(xdr
, &size
));
2090 NS_ASSERTION(data
, "no decoded JSXDRState data!");
2092 rv
= aStream
->Write32(size
);
2093 if (NS_SUCCEEDED(rv
))
2094 rv
= aStream
->WriteBytes(data
, size
);
2097 ::JS_XDRDestroy(xdr
);
2098 if (NS_FAILED(rv
)) return rv
;
2104 nsJSContext::Deserialize(nsIObjectInputStream
* aStream
,
2105 nsScriptObjectHolder
&aResult
)
2107 JSObject
*result
= nsnull
;
2110 NS_TIME_FUNCTION_MIN(1.0);
2112 NS_TIMELINE_MARK_FUNCTION("js script deserialize");
2115 rv
= aStream
->Read32(&size
);
2116 if (NS_FAILED(rv
)) return rv
;
2119 rv
= aStream
->ReadBytes(size
, &data
);
2120 if (NS_FAILED(rv
)) return rv
;
2122 JSContext
* cx
= mContext
;
2124 JSXDRState
*xdr
= ::JS_XDRNewMem(cx
, JSXDR_DECODE
);
2126 rv
= NS_ERROR_OUT_OF_MEMORY
;
2128 xdr
->userdata
= (void*) aStream
;
2129 JSAutoRequest
ar(cx
);
2130 ::JS_XDRMemSetData(xdr
, data
, size
);
2132 JSScript
*script
= nsnull
;
2133 if (! ::JS_XDRScript(xdr
, &script
)) {
2134 rv
= NS_ERROR_FAILURE
; // principals deserialization error?
2136 result
= ::JS_NewScriptObject(cx
, script
);
2138 rv
= NS_ERROR_OUT_OF_MEMORY
; // certain error
2139 ::JS_DestroyScript(cx
, script
);
2143 // Update data in case ::JS_XDRScript called back into C++ code to
2144 // read an XPCOM object.
2146 // In that case, the serialization process must have flushed a run
2147 // of counted bytes containing JS data at the point where the XPCOM
2148 // object starts, after which an encoding C++ callback from the JS
2149 // XDR code must have written the XPCOM object directly into the
2150 // nsIObjectOutputStream.
2152 // The deserialization process will XDR-decode counted bytes up to
2153 // but not including the XPCOM object, then call back into C++ to
2154 // read the object, then read more counted bytes and hand them off
2155 // to the JSXDRState, so more JS data can be decoded.
2157 // This interleaving of JS XDR data and XPCOM object data may occur
2158 // several times beneath the call to ::JS_XDRScript, above. At the
2159 // end of the day, we need to free (via nsMemory) the data owned by
2160 // the JSXDRState. So we steal it back, nulling xdr's buffer so it
2161 // doesn't get passed to ::JS_free by ::JS_XDRDestroy.
2164 data
= (char*) ::JS_XDRMemGetData(xdr
, &junk
);
2166 ::JS_XDRMemSetData(xdr
, NULL
, 0);
2167 ::JS_XDRDestroy(xdr
);
2170 // If data is null now, it must have been freed while deserializing an
2171 // XPCOM object (e.g., a principal) beneath ::JS_XDRScript.
2173 nsMemory::Free(data
);
2174 NS_ASSERTION(aResult
.getScriptTypeID()==JAVASCRIPT
,
2175 "Expecting JS script object holder");
2177 // Now that we've cleaned up, handle the case when rv is a failure
2178 // code, which could happen for all sorts of reasons above.
2179 NS_ENSURE_SUCCESS(rv
, rv
);
2181 return aResult
.set(result
);
2185 nsJSContext::SetDefaultLanguageVersion(PRUint32 aVersion
)
2187 ::JS_SetVersion(mContext
, (JSVersion
)aVersion
);
2190 nsIScriptGlobalObject
*
2191 nsJSContext::GetGlobalObject()
2193 JSObject
*global
= ::JS_GetGlobalObject(mContext
);
2199 OBJ_TO_INNER_OBJECT(mContext
, global
);
2204 JSClass
*c
= JS_GET_CLASS(mContext
, global
);
2206 if (!c
|| ((~c
->flags
) & (JSCLASS_HAS_PRIVATE
|
2207 JSCLASS_PRIVATE_IS_NSISUPPORTS
))) {
2211 nsISupports
*priv
= (nsISupports
*)global
->getPrivate();
2213 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapped_native
=
2214 do_QueryInterface(priv
);
2216 nsCOMPtr
<nsIScriptGlobalObject
> sgo
;
2217 if (wrapped_native
) {
2218 // The global object is a XPConnect wrapped native, the native in
2219 // the wrapper might be the nsIScriptGlobalObject
2221 sgo
= do_QueryWrappedNative(wrapped_native
);
2223 sgo
= do_QueryInterface(priv
);
2226 // This'll return a pointer to something we're about to release, but
2227 // that's ok, the JS object will hold it alive long enough.
2228 nsCOMPtr
<nsPIDOMWindow
> pwin(do_QueryInterface(sgo
));
2232 return static_cast<nsGlobalWindow
*>(pwin
->GetOuterWindow());
2236 nsJSContext::GetNativeGlobal()
2238 return ::JS_GetGlobalObject(mContext
);
2242 nsJSContext::CreateNativeGlobalForInner(
2243 nsIScriptGlobalObject
*aNewInner
,
2245 nsIPrincipal
*aPrincipal
,
2246 void **aNativeGlobal
, nsISupports
**aHolder
)
2248 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2249 PRUint32 flags
= aIsChrome
? nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT
: 0;
2250 nsCOMPtr
<nsIXPConnectJSObjectHolder
> jsholder
;
2252 nsCOMPtr
<nsIPrincipal
> systemPrincipal
;
2254 nsIScriptSecurityManager
*ssm
= nsContentUtils::GetSecurityManager();
2255 ssm
->GetSystemPrincipal(getter_AddRefs(systemPrincipal
));
2259 InitClassesWithNewWrappedGlobal(mContext
,
2260 aNewInner
, NS_GET_IID(nsISupports
),
2261 aIsChrome
? systemPrincipal
.get() : aPrincipal
,
2263 getter_AddRefs(jsholder
));
2266 jsholder
->GetJSObject(reinterpret_cast<JSObject
**>(aNativeGlobal
));
2267 *aHolder
= jsholder
.get();
2268 NS_ADDREF(*aHolder
);
2273 nsJSContext::ConnectToInner(nsIScriptGlobalObject
*aNewInner
, void *aOuterGlobal
)
2275 NS_ENSURE_ARG(aNewInner
);
2276 JSObject
*newInnerJSObject
= (JSObject
*)aNewInner
->GetScriptGlobal(JAVASCRIPT
);
2277 JSObject
*outerGlobal
= (JSObject
*)aOuterGlobal
;
2279 // Now that we're connecting the outer global to the inner one,
2280 // we must have transplanted it. The JS engine tries to maintain
2281 // the global object's compartment as its default compartment,
2282 // so update that now since it might have changed.
2283 JS_SetGlobalObject(mContext
, outerGlobal
);
2284 NS_ASSERTION(JS_GetPrototype(mContext
, outerGlobal
) ==
2285 JS_GetPrototype(mContext
, newInnerJSObject
),
2286 "outer and inner globals should have the same prototype");
2292 nsJSContext::GetNativeContext()
2298 nsJSContext::InitContext()
2300 // Make sure callers of this use
2301 // WillInitializeContext/DidInitializeContext around this call.
2302 NS_ENSURE_TRUE(!mIsInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
2305 return NS_ERROR_OUT_OF_MEMORY
;
2307 ::JS_SetErrorReporter(mContext
, NS_ScriptErrorReporter
);
2313 nsJSContext::CreateOuterObject(nsIScriptGlobalObject
*aGlobalObject
,
2314 nsIScriptGlobalObject
*aCurrentInner
)
2316 mGlobalObjectRef
= aGlobalObject
;
2318 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(aGlobalObject
));
2322 // Flag this window's global object and objects under it as "system",
2323 // for optional automated XPCNativeWrapper construction when chrome JS
2324 // views a content DOM.
2325 flags
= nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT
;
2327 // Always enable E4X for XUL and other chrome content -- there is no
2328 // need to preserve the <!-- script hiding hack from JS-in-HTML daze
2329 // (introduced in 1995 for graceful script degradation in Netscape 1,
2330 // Mosaic, and other pre-JS browsers).
2331 JS_SetOptions(mContext
, JS_GetOptions(mContext
) | JSOPTION_XML
);
2335 NS_NewOuterWindowProxy(mContext
, aCurrentInner
->GetGlobalJSObject());
2337 return NS_ERROR_FAILURE
;
2340 return SetOuterObject(outer
);
2344 nsJSContext::SetOuterObject(void *aOuterObject
)
2346 JSObject
*outer
= static_cast<JSObject
*>(aOuterObject
);
2348 // Force our context's global object to be the outer.
2349 JS_SetGlobalObject(mContext
, outer
);
2351 // NB: JS_SetGlobalObject sets mContext->compartment.
2352 JSObject
*inner
= JS_GetParent(mContext
, outer
);
2354 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2355 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
2356 nsresult rv
= xpc
->GetWrappedNativeOfJSObject(mContext
, inner
,
2357 getter_AddRefs(wrapper
));
2358 NS_ENSURE_SUCCESS(rv
, rv
);
2359 NS_ABORT_IF_FALSE(wrapper
, "bad wrapper");
2361 wrapper
->RefreshPrototype();
2362 JS_SetPrototype(mContext
, outer
, JS_GetPrototype(mContext
, inner
));
2368 nsJSContext::InitOuterWindow()
2370 JSObject
*global
= JS_GetGlobalObject(mContext
);
2371 OBJ_TO_INNER_OBJECT(mContext
, global
);
2373 nsresult rv
= InitClasses(global
); // this will complete global object initialization
2374 NS_ENSURE_SUCCESS(rv
, rv
);
2380 nsJSContext::InitializeExternalClasses()
2382 nsScriptNameSpaceManager
*nameSpaceManager
= nsJSRuntime::GetNameSpaceManager();
2383 NS_ENSURE_TRUE(nameSpaceManager
, NS_ERROR_NOT_INITIALIZED
);
2385 return nameSpaceManager
->InitForContext(this);
2389 nsJSContext::SetProperty(void *aTarget
, const char *aPropName
, nsISupports
*aArgs
)
2392 jsval
*argv
= nsnull
;
2394 JSAutoRequest
ar(mContext
);
2396 js::LazilyConstructed
<nsAutoPoolRelease
> poolRelease
;
2397 js::LazilyConstructed
<js::AutoArrayRooter
> tvr
;
2400 rv
= ConvertSupportsTojsvals(aArgs
, GetNativeGlobal(), &argc
,
2401 &argv
, poolRelease
, tvr
);
2402 NS_ENSURE_SUCCESS(rv
, rv
);
2406 // got the arguments, now attach them.
2408 // window.dialogArguments is supposed to be an array if a JS array
2409 // was passed to showModalDialog(), deal with that here.
2410 if (strcmp(aPropName
, "dialogArguments") == 0 && argc
<= 1) {
2411 vargs
= argc
? argv
[0] : JSVAL_VOID
;
2413 for (PRUint32 i
= 0; i
< argc
; ++i
) {
2414 if (!JS_WrapValue(mContext
, &argv
[i
])) {
2415 return NS_ERROR_FAILURE
;
2419 JSObject
*args
= ::JS_NewArrayObject(mContext
, argc
, argv
);
2420 vargs
= OBJECT_TO_JSVAL(args
);
2423 // Make sure to use JS_DefineProperty here so that we can override
2424 // readonly XPConnect properties here as well (read dialogArguments).
2425 rv
= ::JS_DefineProperty(mContext
, reinterpret_cast<JSObject
*>(aTarget
),
2426 aPropName
, vargs
, nsnull
, nsnull
, 0) ?
2427 NS_OK
: NS_ERROR_FAILURE
;
2433 nsJSContext::ConvertSupportsTojsvals(nsISupports
*aArgs
,
2437 js::LazilyConstructed
<nsAutoPoolRelease
> &aPoolRelease
,
2438 js::LazilyConstructed
<js::AutoArrayRooter
> &aRooter
)
2440 nsresult rv
= NS_OK
;
2442 // If the array implements nsIJSArgArray, just grab the values directly.
2443 nsCOMPtr
<nsIJSArgArray
> fastArray
= do_QueryInterface(aArgs
);
2444 if (fastArray
!= nsnull
)
2445 return fastArray
->GetArgs(aArgc
, reinterpret_cast<void **>(aArgv
));
2447 // Take the slower path converting each item.
2448 // Handle only nsIArray and nsIVariant. nsIArray is only needed for
2449 // SetProperty('arguments', ...);
2454 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2455 NS_ENSURE_TRUE(xpc
, NS_ERROR_UNEXPECTED
);
2459 PRUint32 argCtr
, argCount
;
2460 // This general purpose function may need to convert an arg array
2461 // (window.arguments, event-handler args) and a generic property.
2462 nsCOMPtr
<nsIArray
> argsArray(do_QueryInterface(aArgs
));
2465 rv
= argsArray
->GetLength(&argCount
);
2466 NS_ENSURE_SUCCESS(rv
, rv
);
2470 argCount
= 1; // the nsISupports which is not an array
2473 void *mark
= JS_ARENA_MARK(&mContext
->tempPool
);
2475 size_t nbytes
= argCount
* sizeof(jsval
);
2476 JS_ARENA_ALLOCATE_CAST(argv
, jsval
*, &mContext
->tempPool
, nbytes
);
2477 NS_ENSURE_TRUE(argv
, NS_ERROR_OUT_OF_MEMORY
);
2478 memset(argv
, 0, nbytes
); /* initialize so GC-able */
2480 // Use the caller's auto guards to release and unroot.
2481 aPoolRelease
.construct(&mContext
->tempPool
, mark
);
2482 aRooter
.construct(mContext
, argCount
, argv
);
2485 for (argCtr
= 0; argCtr
< argCount
&& NS_SUCCEEDED(rv
); argCtr
++) {
2486 nsCOMPtr
<nsISupports
> arg
;
2487 jsval
*thisval
= argv
+ argCtr
;
2488 argsArray
->QueryElementAt(argCtr
, NS_GET_IID(nsISupports
),
2489 getter_AddRefs(arg
));
2491 *thisval
= JSVAL_NULL
;
2494 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(arg
));
2495 if (variant
!= nsnull
) {
2496 rv
= xpc
->VariantToJS(mContext
, (JSObject
*)aScope
, variant
,
2499 // And finally, support the nsISupportsPrimitives supplied
2500 // by the AppShell. It generally will pass only strings, but
2501 // as we have code for handling all, we may as well use it.
2502 rv
= AddSupportsPrimitiveTojsvals(arg
, thisval
);
2503 if (rv
== NS_ERROR_NO_INTERFACE
) {
2504 // something else - probably an event object or similar -
2507 // but first, check its not another nsISupportsPrimitive, as
2508 // these are now deprecated for use with script contexts.
2509 nsCOMPtr
<nsISupportsPrimitive
> prim(do_QueryInterface(arg
));
2510 NS_ASSERTION(prim
== nsnull
,
2511 "Don't pass nsISupportsPrimitives - use nsIVariant!");
2513 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
2515 rv
= nsContentUtils::WrapNative(mContext
, (JSObject
*)aScope
, arg
,
2516 &v
, getter_AddRefs(wrapper
));
2517 if (NS_SUCCEEDED(rv
)) {
2524 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(aArgs
));
2526 rv
= xpc
->VariantToJS(mContext
, (JSObject
*)aScope
, variant
, argv
);
2528 NS_ERROR("Not an array, not an interface?");
2529 rv
= NS_ERROR_UNEXPECTED
;
2539 // This really should go into xpconnect somewhere...
2541 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports
*aArg
, jsval
*aArgv
)
2543 NS_PRECONDITION(aArg
, "Empty arg");
2545 nsCOMPtr
<nsISupportsPrimitive
> argPrimitive(do_QueryInterface(aArg
));
2547 return NS_ERROR_NO_INTERFACE
;
2549 JSContext
*cx
= mContext
;
2551 argPrimitive
->GetType(&type
);
2554 case nsISupportsPrimitive::TYPE_CSTRING
: {
2555 nsCOMPtr
<nsISupportsCString
> p(do_QueryInterface(argPrimitive
));
2556 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2563 JSString
*str
= ::JS_NewStringCopyN(cx
, data
.get(), data
.Length());
2564 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2566 *aArgv
= STRING_TO_JSVAL(str
);
2570 case nsISupportsPrimitive::TYPE_STRING
: {
2571 nsCOMPtr
<nsISupportsString
> p(do_QueryInterface(argPrimitive
));
2572 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2578 // cast is probably safe since wchar_t and jschar are expected
2579 // to be equivalent; both unsigned 16-bit entities
2581 ::JS_NewUCStringCopyN(cx
,
2582 reinterpret_cast<const jschar
*>(data
.get()),
2584 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2586 *aArgv
= STRING_TO_JSVAL(str
);
2589 case nsISupportsPrimitive::TYPE_PRBOOL
: {
2590 nsCOMPtr
<nsISupportsPRBool
> p(do_QueryInterface(argPrimitive
));
2591 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2597 *aArgv
= BOOLEAN_TO_JSVAL(data
);
2601 case nsISupportsPrimitive::TYPE_PRUINT8
: {
2602 nsCOMPtr
<nsISupportsPRUint8
> p(do_QueryInterface(argPrimitive
));
2603 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2609 *aArgv
= INT_TO_JSVAL(data
);
2613 case nsISupportsPrimitive::TYPE_PRUINT16
: {
2614 nsCOMPtr
<nsISupportsPRUint16
> p(do_QueryInterface(argPrimitive
));
2615 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2621 *aArgv
= INT_TO_JSVAL(data
);
2625 case nsISupportsPrimitive::TYPE_PRUINT32
: {
2626 nsCOMPtr
<nsISupportsPRUint32
> p(do_QueryInterface(argPrimitive
));
2627 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2633 *aArgv
= INT_TO_JSVAL(data
);
2637 case nsISupportsPrimitive::TYPE_CHAR
: {
2638 nsCOMPtr
<nsISupportsChar
> p(do_QueryInterface(argPrimitive
));
2639 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2645 JSString
*str
= ::JS_NewStringCopyN(cx
, &data
, 1);
2646 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2648 *aArgv
= STRING_TO_JSVAL(str
);
2652 case nsISupportsPrimitive::TYPE_PRINT16
: {
2653 nsCOMPtr
<nsISupportsPRInt16
> p(do_QueryInterface(argPrimitive
));
2654 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2660 *aArgv
= INT_TO_JSVAL(data
);
2664 case nsISupportsPrimitive::TYPE_PRINT32
: {
2665 nsCOMPtr
<nsISupportsPRInt32
> p(do_QueryInterface(argPrimitive
));
2666 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2672 *aArgv
= INT_TO_JSVAL(data
);
2676 case nsISupportsPrimitive::TYPE_FLOAT
: {
2677 nsCOMPtr
<nsISupportsFloat
> p(do_QueryInterface(argPrimitive
));
2678 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2684 JSBool ok
= ::JS_NewNumberValue(cx
, data
, aArgv
);
2685 NS_ENSURE_TRUE(ok
, NS_ERROR_OUT_OF_MEMORY
);
2689 case nsISupportsPrimitive::TYPE_DOUBLE
: {
2690 nsCOMPtr
<nsISupportsDouble
> p(do_QueryInterface(argPrimitive
));
2691 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2697 JSBool ok
= ::JS_NewNumberValue(cx
, data
, aArgv
);
2698 NS_ENSURE_TRUE(ok
, NS_ERROR_OUT_OF_MEMORY
);
2702 case nsISupportsPrimitive::TYPE_INTERFACE_POINTER
: {
2703 nsCOMPtr
<nsISupportsInterfacePointer
> p(do_QueryInterface(argPrimitive
));
2704 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2706 nsCOMPtr
<nsISupports
> data
;
2707 nsIID
*iid
= nsnull
;
2709 p
->GetData(getter_AddRefs(data
));
2710 p
->GetDataIID(&iid
);
2711 NS_ENSURE_TRUE(iid
, NS_ERROR_UNEXPECTED
);
2713 AutoFree
iidGuard(iid
); // Free iid upon destruction.
2715 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
2717 nsresult rv
= nsContentUtils::WrapNative(cx
, ::JS_GetGlobalObject(cx
),
2719 getter_AddRefs(wrapper
));
2720 NS_ENSURE_SUCCESS(rv
, rv
);
2726 case nsISupportsPrimitive::TYPE_ID
:
2727 case nsISupportsPrimitive::TYPE_PRUINT64
:
2728 case nsISupportsPrimitive::TYPE_PRINT64
:
2729 case nsISupportsPrimitive::TYPE_PRTIME
:
2730 case nsISupportsPrimitive::TYPE_VOID
: {
2731 NS_WARNING("Unsupported primitive type used");
2732 *aArgv
= JSVAL_NULL
;
2736 NS_WARNING("Unknown primitive type used");
2737 *aArgv
= JSVAL_NULL
;
2744 #ifdef NS_TRACE_MALLOC
2746 #include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
2754 #include "nsTraceMalloc.h"
2757 CheckUniversalXPConnectForTraceMalloc(JSContext
*cx
)
2759 PRBool hasCap
= PR_FALSE
;
2760 nsresult rv
= nsContentUtils::GetSecurityManager()->
2761 IsCapabilityEnabled("UniversalXPConnect", &hasCap
);
2762 if (NS_SUCCEEDED(rv
) && hasCap
)
2764 JS_ReportError(cx
, "trace-malloc functions require UniversalXPConnect");
2769 TraceMallocDisable(JSContext
*cx
, uintN argc
, jsval
*vp
)
2771 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2774 NS_TraceMallocDisable();
2775 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2780 TraceMallocEnable(JSContext
*cx
, uintN argc
, jsval
*vp
)
2782 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2785 NS_TraceMallocEnable();
2786 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2791 TraceMallocOpenLogFile(JSContext
*cx
, uintN argc
, jsval
*vp
)
2796 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2802 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
2805 JSAutoByteString
filename(cx
, str
);
2808 fd
= open(filename
.ptr(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
2810 JS_ReportError(cx
, "can't open %s: %s", filename
.ptr(), strerror(errno
));
2814 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(fd
));
2819 TraceMallocChangeLogFD(JSContext
*cx
, uintN argc
, jsval
*vp
)
2823 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2829 if (!JS_ValueToECMAInt32(cx
, JS_ARGV(cx
, vp
)[0], &fd
))
2831 oldfd
= NS_TraceMallocChangeLogFD(fd
);
2833 JS_ReportOutOfMemory(cx
);
2837 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(oldfd
));
2842 TraceMallocCloseLogFD(JSContext
*cx
, uintN argc
, jsval
*vp
)
2846 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2849 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2852 if (!JS_ValueToECMAInt32(cx
, JS_ARGV(cx
, vp
)[0], &fd
))
2854 NS_TraceMallocCloseLogFD((int) fd
);
2859 TraceMallocLogTimestamp(JSContext
*cx
, uintN argc
, jsval
*vp
)
2861 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2864 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
2867 JSAutoByteString
caption(cx
, str
);
2870 NS_TraceMallocLogTimestamp(caption
.ptr());
2871 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2876 TraceMallocDumpAllocations(JSContext
*cx
, uintN argc
, jsval
*vp
)
2878 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
2881 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
2884 JSAutoByteString
pathname(cx
, str
);
2887 if (NS_TraceMallocDumpAllocations(pathname
.ptr()) < 0) {
2888 JS_ReportError(cx
, "can't dump to %s: %s", pathname
.ptr(), strerror(errno
));
2891 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2895 static JSFunctionSpec TraceMallocFunctions
[] = {
2896 {"TraceMallocDisable", TraceMallocDisable
, 0, 0},
2897 {"TraceMallocEnable", TraceMallocEnable
, 0, 0},
2898 {"TraceMallocOpenLogFile", TraceMallocOpenLogFile
, 1, 0},
2899 {"TraceMallocChangeLogFD", TraceMallocChangeLogFD
, 1, 0},
2900 {"TraceMallocCloseLogFD", TraceMallocCloseLogFD
, 1, 0},
2901 {"TraceMallocLogTimestamp", TraceMallocLogTimestamp
, 1, 0},
2902 {"TraceMallocDumpAllocations", TraceMallocDumpAllocations
, 1, 0},
2903 {nsnull
, nsnull
, 0, 0}
2906 #endif /* NS_TRACE_MALLOC */
2913 IsJProfAction(struct sigaction
*action
)
2915 return (action
->sa_sigaction
&&
2916 action
->sa_flags
== (SA_RESTART
| SA_SIGINFO
));
2919 void NS_JProfStartProfiling();
2920 void NS_JProfStopProfiling();
2923 JProfStartProfilingJS(JSContext
*cx
, uintN argc
, jsval
*vp
)
2925 NS_JProfStartProfiling();
2929 void NS_JProfStartProfiling()
2931 // Figure out whether we're dealing with SIGPROF, SIGALRM, or
2932 // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
2934 struct sigaction action
;
2936 sigaction(SIGALRM
, nsnull
, &action
);
2937 if (IsJProfAction(&action
)) {
2938 printf("Beginning real-time jprof profiling.\n");
2943 sigaction(SIGPROF
, nsnull
, &action
);
2944 if (IsJProfAction(&action
)) {
2945 printf("Beginning process-time jprof profiling.\n");
2950 sigaction(SIGPOLL
, nsnull
, &action
);
2951 if (IsJProfAction(&action
)) {
2952 printf("Beginning rtc-based jprof profiling.\n");
2957 printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
2961 JProfStopProfilingJS(JSContext
*cx
, uintN argc
, jsval
*vp
)
2963 NS_JProfStopProfiling();
2968 NS_JProfStopProfiling()
2971 printf("Stopped jprof profiling.\n");
2974 static JSFunctionSpec JProfFunctions
[] = {
2975 {"JProfStartProfiling", JProfStartProfilingJS
, 0, 0},
2976 {"JProfStopProfiling", JProfStopProfilingJS
, 0, 0},
2977 {nsnull
, nsnull
, 0, 0}
2980 #endif /* defined(MOZ_JPROF) */
2982 #ifdef MOZ_CALLGRIND
2983 static JSFunctionSpec CallgrindFunctions
[] = {
2984 {"startCallgrind", js_StartCallgrind
, 0, 0},
2985 {"stopCallgrind", js_StopCallgrind
, 0, 0},
2986 {"dumpCallgrind", js_DumpCallgrind
, 1, 0},
2987 {nsnull
, nsnull
, 0, 0}
2992 static JSFunctionSpec VtuneFunctions
[] = {
2993 {"startVtune", js_StartVtune
, 1, 0},
2994 {"stopVtune", js_StopVtune
, 0, 0},
2995 {"pauseVtune", js_PauseVtune
, 0, 0},
2996 {"resumeVtune", js_ResumeVtune
, 0, 0},
2997 {nsnull
, nsnull
, 0, 0}
3002 static JSFunctionSpec EthogramFunctions
[] = {
3003 {"initEthogram", js_InitEthogram
, 0, 0},
3004 {"shutdownEthogram", js_ShutdownEthogram
, 0, 0},
3005 {nsnull
, nsnull
, 0, 0}
3010 nsJSContext::InitClasses(void *aGlobalObj
)
3012 nsresult rv
= NS_OK
;
3014 JSObject
*globalObj
= static_cast<JSObject
*>(aGlobalObj
);
3016 rv
= InitializeExternalClasses();
3017 NS_ENSURE_SUCCESS(rv
, rv
);
3019 JSAutoRequest
ar(mContext
);
3021 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
3023 // Attempt to initialize profiling functions
3024 ::JS_DefineProfilingFunctions(mContext
, globalObj
);
3026 #ifdef NS_TRACE_MALLOC
3027 // Attempt to initialize TraceMalloc functions
3028 ::JS_DefineFunctions(mContext
, globalObj
, TraceMallocFunctions
);
3032 // Attempt to initialize JProf functions
3033 ::JS_DefineFunctions(mContext
, globalObj
, JProfFunctions
);
3036 #ifdef MOZ_CALLGRIND
3037 // Attempt to initialize Callgrind functions
3038 ::JS_DefineFunctions(mContext
, globalObj
, CallgrindFunctions
);
3042 // Attempt to initialize Vtune functions
3043 ::JS_DefineFunctions(mContext
, globalObj
, VtuneFunctions
);
3047 // Attempt to initialize Ethogram functions
3048 ::JS_DefineFunctions(mContext
, globalObj
, EthogramFunctions
);
3051 JSOptionChangedCallback(js_options_dot_str
, this);
3057 nsJSContext::ClearScope(void *aGlobalObj
, PRBool aClearFromProtoChain
)
3059 // Push our JSContext on our thread's context stack.
3060 nsCOMPtr
<nsIJSContextStack
> stack
=
3061 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
3062 if (stack
&& NS_FAILED(stack
->Push(mContext
))) {
3067 JSObject
*obj
= (JSObject
*)aGlobalObj
;
3068 JSAutoRequest
ar(mContext
);
3070 JSAutoEnterCompartment ac
;
3071 ac
.enterAndIgnoreErrors(mContext
, obj
);
3073 // Grab a reference to the window property, which is the outer
3074 // window, so that we can re-define it once we've cleared
3075 // scope. This is what keeps the outer window alive in cases where
3076 // nothing else does.
3078 if (!JS_GetProperty(mContext
, obj
, "window", &window
)) {
3079 window
= JSVAL_VOID
;
3081 JS_ClearPendingException(mContext
);
3084 JS_ClearScope(mContext
, obj
);
3086 NS_ABORT_IF_FALSE(!xpc::WrapperFactory::IsXrayWrapper(obj
), "unexpected wrapper");
3088 if (window
!= JSVAL_VOID
) {
3089 if (!JS_DefineProperty(mContext
, obj
, "window", window
,
3090 JS_PropertyStub
, JS_StrictPropertyStub
,
3091 JSPROP_ENUMERATE
| JSPROP_READONLY
|
3092 JSPROP_PERMANENT
)) {
3093 JS_ClearPendingException(mContext
);
3097 if (!obj
->getParent()) {
3098 JS_ClearRegExpStatics(mContext
, obj
);
3101 // Always clear watchpoints, to deal with two cases:
3102 // 1. The first document for this window is loading, and a miscreant has
3103 // preset watchpoints on the window object in order to attack the new
3104 // document's privileged information.
3105 // 2. A document loaded and used watchpoints on its own window, leaving
3106 // them set until the next document loads. We must clean up window
3107 // watchpoints here.
3108 // Watchpoints set on document and subordinate objects are all cleared
3109 // when those sub-window objects are finalized, after JS_ClearScope and
3110 // a GC run that finds them to be garbage.
3111 ::JS_ClearWatchPointsForObject(mContext
, obj
);
3113 // Since the prototype chain is shared between inner and outer (and
3114 // stays with the inner), we don't clear things from the prototype
3115 // chain when we're clearing an outer window whose current inner we
3117 if (aClearFromProtoChain
) {
3118 nsWindowSH::InvalidateGlobalScopePolluter(mContext
, obj
);
3120 // Clear up obj's prototype chain, but not Object.prototype.
3121 for (JSObject
*o
= ::JS_GetPrototype(mContext
, obj
), *next
;
3122 o
&& (next
= ::JS_GetPrototype(mContext
, o
)); o
= next
)
3123 ::JS_ClearScope(mContext
, o
);
3133 nsJSContext::WillInitializeContext()
3135 mIsInitialized
= PR_FALSE
;
3139 nsJSContext::DidInitializeContext()
3141 mIsInitialized
= PR_TRUE
;
3145 nsJSContext::IsContextInitialized()
3147 return mIsInitialized
;
3151 nsJSContext::FinalizeContext()
3157 nsJSContext::ScriptEvaluated(PRBool aTerminated
)
3159 if (aTerminated
&& mTerminations
) {
3160 // Make sure to null out mTerminations before doing anything that
3161 // might cause new termination funcs to be added!
3162 nsJSContext::TerminationFuncClosure
* start
= mTerminations
;
3163 mTerminations
= nsnull
;
3165 for (nsJSContext::TerminationFuncClosure
* cur
= start
;
3168 (*(cur
->mTerminationFunc
))(cur
->mTerminationFuncArg
);
3173 JS_MaybeGC(mContext
);
3176 mOperationCallbackTime
= 0;
3177 mModalStateTime
= 0;
3182 nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc
,
3185 NS_PRECONDITION(GetExecutingScript(), "should be executing script");
3187 nsJSContext::TerminationFuncClosure
* newClosure
=
3188 new nsJSContext::TerminationFuncClosure(aFunc
, aRef
, mTerminations
);
3190 return NS_ERROR_OUT_OF_MEMORY
;
3193 mTerminations
= newClosure
;
3198 nsJSContext::GetScriptsEnabled()
3200 return mScriptsEnabled
;
3204 nsJSContext::SetScriptsEnabled(PRBool aEnabled
, PRBool aFireTimeouts
)
3206 // eeek - this seems the wrong way around - the global should callback
3207 // into each context, so every language is disabled.
3208 mScriptsEnabled
= aEnabled
;
3210 nsIScriptGlobalObject
*global
= GetGlobalObject();
3213 global
->SetScriptsEnabled(aEnabled
, aFireTimeouts
);
3219 nsJSContext::GetProcessingScriptTag()
3221 return mProcessingScriptTag
;
3225 nsJSContext::SetProcessingScriptTag(PRBool aFlag
)
3227 mProcessingScriptTag
= aFlag
;
3231 nsJSContext::GetExecutingScript()
3233 return JS_IsRunning(mContext
) || mExecuteDepth
> 0;
3237 nsJSContext::SetGCOnDestruction(PRBool aGCOnDestruction
)
3239 mGCOnDestruction
= aGCOnDestruction
;
3243 nsJSContext::ScriptExecuted()
3245 ScriptEvaluated(!::JS_IsRunning(mContext
));
3252 nsJSContext::GarbageCollectNow()
3254 NS_TIME_FUNCTION_MIN(1.0);
3258 // Reset sPendingLoadCount in case the timer that fired was a
3259 // timer we scheduled due to a normal GC timer firing while
3260 // documents were loading. If this happens we're waiting for a
3261 // document that is taking a long time to load, and we effectively
3262 // ignore the fact that the currently loading documents are still
3263 // loading and move on as if they weren't.
3264 sPendingLoadCount
= 0;
3265 sLoadingInProgress
= PR_FALSE
;
3267 nsContentUtils::XPConnect()->GarbageCollect();
3272 nsJSContext::CycleCollectNow(nsICycleCollectorListener
*aListener
)
3274 if (!NS_IsMainThread()) {
3278 NS_TIME_FUNCTION_MIN(1.0);
3282 PRTime start
= PR_Now();
3284 PRUint32 suspected
= nsCycleCollector_suspectedCount();
3285 PRUint32 collected
= nsCycleCollector_collect(aListener
);
3287 // If we collected cycles, poke the GC since more objects might be unreachable now.
3288 if (collected
> 0) {
3292 if (sPostGCEventsToConsole
) {
3293 PRTime now
= PR_Now();
3294 NS_NAMED_LITERAL_STRING(kFmt
,
3295 "CC timestamp: %lld, collected: %lu, suspected: %lu, duration: %llu ms.");
3297 msg
.Adopt(nsTextFormatter::smprintf(kFmt
.get(), now
,
3298 collected
, suspected
,
3299 (now
- start
) / PR_USEC_PER_MSEC
));
3300 nsCOMPtr
<nsIConsoleService
> cs
=
3301 do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
3303 cs
->LogStringMessage(msg
.get());
3310 GCTimerFired(nsITimer
*aTimer
, void *aClosure
)
3312 NS_RELEASE(sGCTimer
);
3314 nsJSContext::GarbageCollectNow();
3319 CCTimerFired(nsITimer
*aTimer
, void *aClosure
)
3321 NS_RELEASE(sCCTimer
);
3323 nsJSContext::CycleCollectNow();
3328 nsJSContext::LoadStart()
3330 sLoadingInProgress
= PR_TRUE
;
3331 ++sPendingLoadCount
;
3336 nsJSContext::LoadEnd()
3338 if (!sLoadingInProgress
)
3341 // sPendingLoadCount is not a well managed load counter (and doesn't
3342 // need to be), so make sure we don't make it wrap backwards here.
3343 if (sPendingLoadCount
> 0) {
3344 --sPendingLoadCount
;
3348 // Its probably a good idea to GC soon since we have finished loading.
3349 sLoadingInProgress
= PR_FALSE
;
3355 nsJSContext::PokeGC()
3358 // There's already a timer for GC'ing, just return
3362 CallCreateInstance("@mozilla.org/timer;1", &sGCTimer
);
3365 NS_WARNING("Failed to create timer");
3367 GarbageCollectNow();
3371 static PRBool first
= PR_TRUE
;
3373 sGCTimer
->InitWithFuncCallback(GCTimerFired
, nsnull
,
3377 nsITimer::TYPE_ONE_SHOT
);
3384 nsJSContext::MaybePokeCC()
3386 if (nsCycleCollector_suspectedCount() > 1000) {
3393 nsJSContext::PokeCC()
3396 // There's already a timer for GC'ing, just return
3400 CallCreateInstance("@mozilla.org/timer;1", &sCCTimer
);
3403 NS_WARNING("Failed to create timer");
3409 sCCTimer
->InitWithFuncCallback(CCTimerFired
, nsnull
,
3411 nsITimer::TYPE_ONE_SHOT
);
3416 nsJSContext::KillGCTimer()
3421 NS_RELEASE(sGCTimer
);
3427 nsJSContext::KillCCTimer()
3432 NS_RELEASE(sCCTimer
);
3443 DOMGCCallback(JSContext
*cx
, JSGCStatus status
)
3445 static PRTime start
;
3447 if (sPostGCEventsToConsole
&& NS_IsMainThread()) {
3448 if (status
== JSGC_BEGIN
) {
3450 } else if (status
== JSGC_END
) {
3451 PRTime now
= PR_Now();
3452 NS_NAMED_LITERAL_STRING(kFmt
, "GC timestamp: %lld, duration: %llu ms.");
3454 msg
.Adopt(nsTextFormatter::smprintf(kFmt
.get(), now
,
3455 (now
- start
) / PR_USEC_PER_MSEC
));
3456 nsCOMPtr
<nsIConsoleService
> cs
= do_GetService(NS_CONSOLESERVICE_CONTRACTID
);
3458 cs
->LogStringMessage(msg
.get());
3463 if (status
== JSGC_END
) {
3465 // If we were waiting for a GC to happen, kill the timer.
3466 nsJSContext::KillGCTimer();
3468 // If this is a compartment GC, restart it. We still want
3469 // a full GC to happen. Compartment GCs usually happen as a
3470 // result of last-ditch or MaybeGC. In both cases its
3471 // probably a time of heavy activity and we want to delay
3472 // the full GC, but we do want it to happen eventually.
3473 if (cx
->runtime
->gcTriggerCompartment
) {
3474 nsJSContext::PokeGC();
3476 // We poked the GC, so we can kill any pending CC here.
3477 nsJSContext::KillCCTimer();
3480 // If this was a full GC, poke the CC to run soon.
3481 if (!cx
->runtime
->gcTriggerCompartment
) {
3482 nsJSContext::PokeCC();
3487 JSBool result
= gOldJSGCCallback
? gOldJSGCCallback(cx
, status
) : JS_TRUE
;
3489 if (status
== JSGC_BEGIN
&& !NS_IsMainThread())
3495 // Script object mananagement - note duplicate implementation
3496 // in nsJSRuntime below...
3498 nsJSContext::HoldScriptObject(void* aScriptObject
)
3500 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3501 if (! nsJSRuntime::sRuntime
) {
3502 NS_NOTREACHED("couldn't add GC root - no runtime");
3503 return NS_ERROR_FAILURE
;
3506 ::JS_LockGCThingRT(nsJSRuntime::sRuntime
, aScriptObject
);
3511 nsJSContext::DropScriptObject(void* aScriptObject
)
3513 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3514 if (! nsJSRuntime::sRuntime
) {
3515 NS_NOTREACHED("couldn't remove GC root");
3516 return NS_ERROR_FAILURE
;
3519 ::JS_UnlockGCThingRT(nsJSRuntime::sRuntime
, aScriptObject
);
3524 nsJSContext::ReportPendingException()
3526 // set aside the frame chain, since it has nothing to do with the
3527 // exception we're reporting.
3528 if (mIsInitialized
&& ::JS_IsExceptionPending(mContext
)) {
3529 JSStackFrame
* frame
= JS_SaveFrameChain(mContext
);
3530 ::JS_ReportPendingException(mContext
);
3531 JS_RestoreFrameChain(mContext
, frame
);
3535 /**********************************************************************
3536 * nsJSRuntime implementation
3537 *********************************************************************/
3539 // QueryInterface implementation for nsJSRuntime
3540 NS_INTERFACE_MAP_BEGIN(nsJSRuntime
)
3541 NS_INTERFACE_MAP_ENTRY(nsIScriptRuntime
)
3542 NS_INTERFACE_MAP_END
3545 NS_IMPL_ADDREF(nsJSRuntime
)
3546 NS_IMPL_RELEASE(nsJSRuntime
)
3549 nsJSRuntime::CreateContext(nsIScriptContext
**aContext
)
3551 nsCOMPtr
<nsIScriptContext
> scriptContext
;
3553 *aContext
= new nsJSContext(sRuntime
);
3554 NS_ENSURE_TRUE(*aContext
, NS_ERROR_OUT_OF_MEMORY
);
3555 NS_ADDREF(*aContext
);
3560 nsJSRuntime::ParseVersion(const nsString
&aVersionStr
, PRUint32
*flags
)
3562 NS_PRECONDITION(flags
, "Null flags param?");
3563 JSVersion jsVersion
= JSVERSION_UNKNOWN
;
3564 if (aVersionStr
.Length() != 3 || aVersionStr
[0] != '1' || aVersionStr
[1] != '.')
3565 jsVersion
= JSVERSION_UNKNOWN
;
3566 else switch (aVersionStr
[2]) {
3567 case '0': jsVersion
= JSVERSION_1_0
; break;
3568 case '1': jsVersion
= JSVERSION_1_1
; break;
3569 case '2': jsVersion
= JSVERSION_1_2
; break;
3570 case '3': jsVersion
= JSVERSION_1_3
; break;
3571 case '4': jsVersion
= JSVERSION_1_4
; break;
3572 case '5': jsVersion
= JSVERSION_1_5
; break;
3573 case '6': jsVersion
= JSVERSION_1_6
; break;
3574 case '7': jsVersion
= JSVERSION_1_7
; break;
3575 case '8': jsVersion
= JSVERSION_1_8
; break;
3576 default: jsVersion
= JSVERSION_UNKNOWN
;
3578 *flags
= (PRUint32
)jsVersion
;
3584 nsJSRuntime::Startup()
3586 // initialize all our statics, so that we can restart XPCOM
3587 sGCTimer
= sCCTimer
= nsnull
;
3588 sPendingLoadCount
= 0;
3589 sLoadingInProgress
= PR_FALSE
;
3590 sPostGCEventsToConsole
= PR_FALSE
;
3591 gNameSpaceManager
= nsnull
;
3592 sRuntimeService
= nsnull
;
3594 gOldJSGCCallback
= nsnull
;
3595 sIsInitialized
= PR_FALSE
;
3596 sDidShutdown
= PR_FALSE
;
3598 sSecurityManager
= nsnull
;
3602 MaxScriptRunTimePrefChangedCallback(const char *aPrefName
, void *aClosure
)
3604 // Default limit on script run time to 10 seconds. 0 means let
3605 // scripts run forever.
3606 PRBool isChromePref
=
3607 strcmp(aPrefName
, "dom.max_chrome_script_run_time") == 0;
3608 PRInt32 time
= nsContentUtils::GetIntPref(aPrefName
, isChromePref
? 20 : 10);
3612 // Let scripts run for a really, really long time.
3613 t
= LL_INIT(0x40000000, 0);
3615 t
= time
* PR_USEC_PER_SEC
;
3619 sMaxChromeScriptRunTime
= t
;
3621 sMaxScriptRunTime
= t
;
3628 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3630 PRBool reportAll
= nsContentUtils::GetBoolPref(aPrefName
, PR_FALSE
);
3631 nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll
);
3636 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3638 PRInt32 highwatermark
= nsContentUtils::GetIntPref(aPrefName
, 128);
3640 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_MALLOC_BYTES
,
3641 highwatermark
* 1024L * 1024L);
3646 SetMemoryMaxPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3648 PRInt32 pref
= nsContentUtils::GetIntPref(aPrefName
, -1);
3649 // handle overflow and negative pref values
3650 PRUint32 max
= (pref
<= 0 || pref
>= 0x1000) ? -1 : (PRUint32
)pref
* 1024 * 1024;
3651 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_BYTES
, max
);
3656 SetMemoryGCFrequencyPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3658 PRInt32 triggerFactor
= nsContentUtils::GetIntPref(aPrefName
, 300);
3659 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_TRIGGER_FACTOR
, triggerFactor
);
3664 SetMemoryGCModePrefChangedCallback(const char* aPrefName
, void* aClosure
)
3666 PRBool enableCompartmentGC
= nsContentUtils::GetBoolPref(aPrefName
);
3667 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MODE
, enableCompartmentGC
3668 ? JSGC_MODE_COMPARTMENT
3669 : JSGC_MODE_GLOBAL
);
3673 static JSPrincipals
*
3674 ObjectPrincipalFinder(JSContext
*cx
, JSObject
*obj
)
3676 if (!sSecurityManager
)
3679 nsCOMPtr
<nsIPrincipal
> principal
;
3681 sSecurityManager
->GetObjectPrincipal(cx
, obj
,
3682 getter_AddRefs(principal
));
3684 if (NS_FAILED(rv
) || !principal
) {
3688 JSPrincipals
*jsPrincipals
= nsnull
;
3689 principal
->GetJSPrincipals(cx
, &jsPrincipals
);
3691 // nsIPrincipal::GetJSPrincipals() returns a strong reference to the
3692 // JS principals, but the caller of this function expects a weak
3693 // reference. So we need to release here.
3695 JSPRINCIPALS_DROP(cx
, jsPrincipals
);
3697 return jsPrincipals
;
3701 DOMReadStructuredClone(JSContext
* cx
,
3702 JSStructuredCloneReader
* reader
,
3707 // We don't currently support any extensions to structured cloning.
3708 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3713 DOMWriteStructuredClone(JSContext
* cx
,
3714 JSStructuredCloneWriter
* writer
,
3718 // We don't currently support any extensions to structured cloning.
3719 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3724 DOMStructuredCloneError(JSContext
* cx
,
3727 // We don't currently support any extensions to structured cloning.
3728 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3735 if (sIsInitialized
) {
3736 if (!nsContentUtils::XPConnect())
3737 return NS_ERROR_NOT_AVAILABLE
;
3742 nsresult rv
= CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
,
3744 NS_ENSURE_SUCCESS(rv
, rv
);
3746 rv
= CallGetService(kJSRuntimeServiceContractID
, &sRuntimeService
);
3747 // get the JSRuntime from the runtime svc, if possible
3748 NS_ENSURE_SUCCESS(rv
, rv
);
3750 rv
= sRuntimeService
->GetRuntime(&sRuntime
);
3751 NS_ENSURE_SUCCESS(rv
, rv
);
3753 // Let's make sure that our main thread is the same as the xpcom main thread.
3754 NS_ASSERTION(NS_IsMainThread(), "bad");
3756 NS_ASSERTION(!gOldJSGCCallback
,
3757 "nsJSRuntime initialized more than once");
3759 // Save the old GC callback to chain to it, for GC-observing generality.
3760 gOldJSGCCallback
= ::JS_SetGCCallbackRT(sRuntime
, DOMGCCallback
);
3762 JSSecurityCallbacks
*callbacks
= JS_GetRuntimeSecurityCallbacks(sRuntime
);
3763 NS_ASSERTION(callbacks
, "SecMan should have set security callbacks!");
3765 callbacks
->findObjectPrincipals
= ObjectPrincipalFinder
;
3767 // Set up the structured clone callbacks.
3768 static JSStructuredCloneCallbacks cloneCallbacks
= {
3769 DOMReadStructuredClone
,
3770 DOMWriteStructuredClone
,
3771 DOMStructuredCloneError
3773 JS_SetStructuredCloneCallbacks(sRuntime
, &cloneCallbacks
);
3775 // Set these global xpconnect options...
3776 nsContentUtils::RegisterPrefCallback("dom.max_script_run_time",
3777 MaxScriptRunTimePrefChangedCallback
,
3779 MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull
);
3781 nsContentUtils::RegisterPrefCallback("dom.max_chrome_script_run_time",
3782 MaxScriptRunTimePrefChangedCallback
,
3784 MaxScriptRunTimePrefChangedCallback("dom.max_chrome_script_run_time",
3787 nsContentUtils::RegisterPrefCallback("dom.report_all_js_exceptions",
3788 ReportAllJSExceptionsPrefChangedCallback
,
3790 ReportAllJSExceptionsPrefChangedCallback("dom.report_all_js_exceptions",
3793 nsContentUtils::RegisterPrefCallback("javascript.options.mem.high_water_mark",
3794 SetMemoryHighWaterMarkPrefChangedCallback
,
3796 SetMemoryHighWaterMarkPrefChangedCallback("javascript.options.mem.high_water_mark",
3799 nsContentUtils::RegisterPrefCallback("javascript.options.mem.max",
3800 SetMemoryMaxPrefChangedCallback
,
3802 SetMemoryMaxPrefChangedCallback("javascript.options.mem.max",
3805 nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_frequency",
3806 SetMemoryGCFrequencyPrefChangedCallback
,
3808 SetMemoryGCFrequencyPrefChangedCallback("javascript.options.mem.gc_frequency",
3811 nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_per_compartment",
3812 SetMemoryGCModePrefChangedCallback
,
3814 SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_per_compartment",
3817 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
3819 return NS_ERROR_FAILURE
;
3821 nsIObserver
* memPressureObserver
= new nsMemoryPressureObserver();
3822 NS_ENSURE_TRUE(memPressureObserver
, NS_ERROR_OUT_OF_MEMORY
);
3823 obs
->AddObserver(memPressureObserver
, "memory-pressure", PR_FALSE
);
3825 sIsInitialized
= PR_TRUE
;
3831 nsScriptNameSpaceManager
*
3832 nsJSRuntime::GetNameSpaceManager()
3837 if (!gNameSpaceManager
) {
3838 gNameSpaceManager
= new nsScriptNameSpaceManager
;
3839 NS_ADDREF(gNameSpaceManager
);
3841 nsresult rv
= gNameSpaceManager
->Init();
3842 NS_ENSURE_SUCCESS(rv
, nsnull
);
3845 return gNameSpaceManager
;
3850 nsJSRuntime::Shutdown()
3852 nsJSContext::KillGCTimer();
3853 nsJSContext::KillCCTimer();
3855 NS_IF_RELEASE(gNameSpaceManager
);
3857 if (!sContextCount
) {
3858 // We're being shutdown, and there are no more contexts
3859 // alive, release the JS runtime service and the security manager.
3861 if (sRuntimeService
&& sSecurityManager
) {
3862 JSSecurityCallbacks
*callbacks
= JS_GetRuntimeSecurityCallbacks(sRuntime
);
3864 NS_ASSERTION(callbacks
->findObjectPrincipals
== ObjectPrincipalFinder
,
3865 "Fighting over the findObjectPrincipals callback!");
3866 callbacks
->findObjectPrincipals
= NULL
;
3869 NS_IF_RELEASE(sRuntimeService
);
3870 NS_IF_RELEASE(sSecurityManager
);
3873 sDidShutdown
= PR_TRUE
;
3876 // Script object mananagement - note duplicate implementation
3877 // in nsJSContext above...
3879 nsJSRuntime::HoldScriptObject(void* aScriptObject
)
3881 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3883 NS_NOTREACHED("couldn't remove GC root - no runtime");
3884 return NS_ERROR_FAILURE
;
3887 ::JS_LockGCThingRT(sRuntime
, aScriptObject
);
3892 nsJSRuntime::DropScriptObject(void* aScriptObject
)
3894 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3896 NS_NOTREACHED("couldn't remove GC root");
3897 return NS_ERROR_FAILURE
;
3900 ::JS_UnlockGCThingRT(sRuntime
, aScriptObject
);
3904 // A factory for the runtime.
3905 nsresult
NS_CreateJSRuntime(nsIScriptRuntime
**aRuntime
)
3907 nsresult rv
= nsJSRuntime::Init();
3908 NS_ENSURE_SUCCESS(rv
, rv
);
3910 *aRuntime
= new nsJSRuntime();
3911 if (*aRuntime
== nsnull
)
3912 return NS_ERROR_OUT_OF_MEMORY
;
3913 NS_IF_ADDREF(*aRuntime
);
3917 // A fast-array class for JS. This class supports both nsIJSScriptArray and
3918 // nsIArray. If it is JS itself providing and consuming this class, all work
3919 // can be done via nsIJSScriptArray, and avoid the conversion of elements
3920 // to/from nsISupports.
3921 // When consumed by non-JS (eg, another script language), conversion is done
3923 class nsJSArgArray
: public nsIJSArgArray
, public nsIArray
{
3925 nsJSArgArray(JSContext
*aContext
, PRUint32 argc
, jsval
*argv
, nsresult
*prv
);
3928 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
3929 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray
,
3936 nsresult
GetArgs(PRUint32
*argc
, void **argv
);
3938 void ReleaseJSObjects();
3941 JSContext
*mContext
;
3946 nsJSArgArray::nsJSArgArray(JSContext
*aContext
, PRUint32 argc
, jsval
*argv
,
3952 // copy the array - we don't know its lifetime, and ours is tied to xpcom
3953 // refcounting. Alloc zero'd array so cleanup etc is safe.
3955 mArgv
= (jsval
*) PR_CALLOC(argc
* sizeof(jsval
));
3957 *prv
= NS_ERROR_OUT_OF_MEMORY
;
3962 // Callers are allowed to pass in a null argv even for argc > 0. They can
3963 // then use GetArgs to initialize the values.
3965 for (PRUint32 i
= 0; i
< argc
; ++i
)
3969 *prv
= argc
> 0 ? NS_HOLD_JS_OBJECTS(this, nsJSArgArray
) : NS_OK
;
3972 nsJSArgArray::~nsJSArgArray()
3978 nsJSArgArray::ReleaseJSObjects()
3981 NS_DROP_JS_OBJECTS(this, nsJSArgArray
);
3988 // QueryInterface implementation for nsJSArgArray
3989 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray
)
3990 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSArgArray
)
3991 tmp
->ReleaseJSObjects();
3992 NS_IMPL_CYCLE_COLLECTION_ROOT_END
3993 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsJSArgArray
)
3994 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray
)
3995 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
3996 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
3998 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray
)
3999 jsval
*argv
= tmp
->mArgv
;
4002 for (end
= argv
+ tmp
->mArgc
; argv
< end
; ++argv
) {
4003 if (JSVAL_IS_GCTHING(*argv
))
4004 NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT
,
4005 JSVAL_TO_GCTHING(*argv
))
4008 NS_IMPL_CYCLE_COLLECTION_TRACE_END
4010 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray
)
4011 NS_INTERFACE_MAP_ENTRY(nsIArray
)
4012 NS_INTERFACE_MAP_ENTRY(nsIJSArgArray
)
4013 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSArgArray
)
4014 NS_INTERFACE_MAP_END
4016 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSArgArray
, nsIJSArgArray
)
4017 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSArgArray
, nsIJSArgArray
)
4020 nsJSArgArray::GetArgs(PRUint32
*argc
, void **argv
)
4023 NS_WARNING("nsJSArgArray has no argv!");
4024 return NS_ERROR_UNEXPECTED
;
4026 *argv
= (void *)mArgv
;
4032 NS_IMETHODIMP
nsJSArgArray::GetLength(PRUint32
*aLength
)
4038 /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
4039 NS_IMETHODIMP
nsJSArgArray::QueryElementAt(PRUint32 index
, const nsIID
& uuid
, void * *result
)
4043 return NS_ERROR_INVALID_ARG
;
4045 if (uuid
.Equals(NS_GET_IID(nsIVariant
)) || uuid
.Equals(NS_GET_IID(nsISupports
))) {
4046 return nsContentUtils::XPConnect()->JSToVariant(mContext
, mArgv
[index
],
4047 (nsIVariant
**)result
);
4049 NS_WARNING("nsJSArgArray only handles nsIVariant");
4050 return NS_ERROR_NO_INTERFACE
;
4053 /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
4054 NS_IMETHODIMP
nsJSArgArray::IndexOf(PRUint32 startIndex
, nsISupports
*element
, PRUint32
*_retval
)
4056 return NS_ERROR_NOT_IMPLEMENTED
;
4059 /* nsISimpleEnumerator enumerate (); */
4060 NS_IMETHODIMP
nsJSArgArray::Enumerate(nsISimpleEnumerator
**_retval
)
4062 return NS_ERROR_NOT_IMPLEMENTED
;
4065 // The factory function
4066 nsresult
NS_CreateJSArgv(JSContext
*aContext
, PRUint32 argc
, void *argv
,
4070 nsJSArgArray
*ret
= new nsJSArgArray(aContext
, argc
,
4071 static_cast<jsval
*>(argv
), &rv
);
4073 return NS_ERROR_OUT_OF_MEMORY
;
4074 if (NS_FAILED(rv
)) {
4078 return ret
->QueryInterface(NS_GET_IID(nsIArray
), (void **)aArray
);