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 // For locale aware string methods
89 #include "nsIPlatformCharset.h"
90 #include "nsICharsetConverterManager.h"
91 #include "nsUnicharUtils.h"
92 #include "nsILocaleService.h"
93 #include "nsICollation.h"
94 #include "nsCollationCID.h"
95 #include "nsDOMClassInfo.h"
97 #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
100 #include "nsIObjectInputStream.h"
101 #include "nsIObjectOutputStream.h"
102 #include "nsITimelineService.h"
103 #include "nsDOMScriptObjectHolder.h"
105 #include "WrapperFactory.h"
106 #include "nsGlobalWindow.h"
109 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
112 #include "AccessCheck.h"
114 #ifdef MOZ_JSDEBUGGER
115 #include "jsdIDebuggerService.h"
118 // Force PR_LOGGING so we can get JS strict warnings even in release builds
119 #define FORCE_PR_LOG 1
122 #include "prthread.h"
124 #include "mozilla/FunctionTimer.h"
126 const size_t gStackSize
= 8192;
129 static PRLogModuleInfo
* gJSDiagnostics
;
132 // Thank you Microsoft!
139 // The amount of time we wait between a request to GC (due to leaving
140 // a page) and doing the actual GC.
141 #define NS_GC_DELAY 2000 // ms
143 // The amount of time we wait until we force a GC in case the previous
144 // GC timer happened to fire while we were in the middle of loading a
145 // page (we'll GC once the page is loaded if that happens before this
146 // amount of time has passed).
147 #define NS_LOAD_IN_PROCESS_GC_DELAY 4000 // ms
149 // The amount of time we wait from the first request to GC to actually
150 // doing the first GC.
151 #define NS_FIRST_GC_DELAY 10000 // ms
153 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
155 // The max number of delayed cycle collects..
156 #define NS_MAX_DELAYED_CCOLLECT 45
157 // The max number of user interaction notifications in inactive state before
158 // we try to call cycle collector more aggressively.
159 #define NS_CC_SOFT_LIMIT_INACTIVE 6
160 // The max number of user interaction notifications in active state before
161 // we try to call cycle collector more aggressively.
162 #define NS_CC_SOFT_LIMIT_ACTIVE 12
163 // When higher probability MaybeCC is used, the number of sDelayedCCollectCount
164 // is multiplied with this number.
165 #define NS_PROBABILITY_MULTIPLIER 3
166 // Cycle collector is never called more often than every NS_MIN_CC_INTERVAL
167 // milliseconds. Exceptions are low memory situation and memory pressure
169 #define NS_MIN_CC_INTERVAL 10000 // ms
170 // If previous cycle collection collected more than this number of objects,
171 // the next collection will happen somewhat soon.
172 #define NS_COLLECTED_OBJECTS_LIMIT 5000
173 // CC will be called if GC has been called at least this number of times and
174 // there are at least NS_MIN_SUSPECT_CHANGES new suspected objects.
175 #define NS_MAX_GC_COUNT 5
176 #define NS_MIN_SUSPECT_CHANGES 10
177 // CC will be called if there are at least NS_MAX_SUSPECT_CHANGES new suspected
179 #define NS_MAX_SUSPECT_CHANGES 100
181 // if you add statics here, add them to the list in nsJSRuntime::Startup
183 static PRUint32 sDelayedCCollectCount
;
184 static PRUint32 sCCollectCount
;
185 static PRBool sUserIsActive
;
186 static PRTime sPreviousCCTime
;
187 static PRUint32 sCollectedObjectsCounts
;
188 static PRUint32 sSavedGCCount
;
189 static PRUint32 sCCSuspectChanges
;
190 static PRUint32 sCCSuspectedCount
;
191 static nsITimer
*sGCTimer
;
192 static PRBool sReadyForGC
;
194 // The number of currently pending document loads. This count isn't
195 // guaranteed to always reflect reality and can't easily as we don't
196 // have an easy place to know when a load ends or is interrupted in
197 // all cases. This counter also gets reset if we end up GC'ing while
198 // we're waiting for a slow page to load. IOW, this count may be 0
199 // even when there are pending loads.
200 static PRUint32 sPendingLoadCount
;
202 // Boolean that tells us whether or not the current GC timer
203 // (sGCTimer) was scheduled due to a GC timer firing while we were in
204 // the middle of loading a page.
205 static PRBool sLoadInProgressGCTimer
;
207 nsScriptNameSpaceManager
*gNameSpaceManager
;
209 static nsIJSRuntimeService
*sRuntimeService
;
210 JSRuntime
*nsJSRuntime::sRuntime
;
212 static const char kJSRuntimeServiceContractID
[] =
213 "@mozilla.org/js/xpc/RuntimeService;1";
215 static JSGCCallback gOldJSGCCallback
;
217 static PRBool sIsInitialized
;
218 static PRBool sDidShutdown
;
220 static PRInt32 sContextCount
;
222 static PRTime sMaxScriptRunTime
;
223 static PRTime sMaxChromeScriptRunTime
;
225 static nsIScriptSecurityManager
*sSecurityManager
;
227 static nsICollation
*gCollation
;
229 static nsIUnicodeDecoder
*gDecoder
;
231 // nsUserActivityObserver observes user-interaction-active and
232 // user-interaction-inactive notifications. It counts the number of
233 // notifications and if the number is bigger than NS_CC_SOFT_LIMIT_ACTIVE
234 // (in case the current notification is user-interaction-active) or
235 // NS_CC_SOFT_LIMIT_INACTIVE (current notification is user-interaction-inactive)
236 // MaybeCC is called with aHigherParameter set to PR_TRUE, otherwise PR_FALSE.
238 // When moving from active state to inactive, nsJSContext::IntervalCC() is
239 // called unless the timer related to page load is active.
241 class nsUserActivityObserver
: public nsIObserver
244 nsUserActivityObserver()
245 : mUserActivityCounter(0), mOldCCollectCount(0) {}
249 PRUint32 mUserActivityCounter
;
250 PRUint32 mOldCCollectCount
;
253 NS_IMPL_ISUPPORTS1(nsUserActivityObserver
, nsIObserver
)
256 nsUserActivityObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
257 const PRUnichar
* aData
)
259 if (mOldCCollectCount
!= sCCollectCount
) {
260 mOldCCollectCount
= sCCollectCount
;
261 // Cycle collector was called between user interaction notifications, so
262 // we can reset the counter.
263 mUserActivityCounter
= 0;
265 PRBool higherProbability
= PR_FALSE
;
266 ++mUserActivityCounter
;
267 if (!strcmp(aTopic
, "user-interaction-inactive")) {
269 printf("user-interaction-inactive\n");
272 sUserIsActive
= PR_FALSE
;
274 nsJSContext::IntervalCC();
278 higherProbability
= (mUserActivityCounter
> NS_CC_SOFT_LIMIT_INACTIVE
);
279 } else if (!strcmp(aTopic
, "user-interaction-active")) {
281 printf("user-interaction-active\n");
283 sUserIsActive
= PR_TRUE
;
284 higherProbability
= (mUserActivityCounter
> NS_CC_SOFT_LIMIT_ACTIVE
);
285 } else if (!strcmp(aTopic
, "xpcom-shutdown")) {
286 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
288 obs
->RemoveObserver(this, "user-interaction-active");
289 obs
->RemoveObserver(this, "user-interaction-inactive");
290 obs
->RemoveObserver(this, "xpcom-shutdown");
294 nsJSContext::MaybeCC(higherProbability
);
298 // nsCCMemoryPressureObserver observes the memory-pressure notifications
299 // and forces a cycle collection when it happens.
301 class nsCCMemoryPressureObserver
: public nsIObserver
308 NS_IMPL_ISUPPORTS1(nsCCMemoryPressureObserver
, nsIObserver
)
311 nsCCMemoryPressureObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
312 const PRUnichar
* aData
)
314 nsJSContext::CC(nsnull
);
318 /****************************************************************
319 ************************** AutoFree ****************************
320 ****************************************************************/
324 AutoFree(void *aPtr
) : mPtr(aPtr
) {
328 nsMemory::Free(mPtr
);
337 class nsAutoPoolRelease
{
339 nsAutoPoolRelease(JSArenaPool
*p
, void *m
) : mPool(p
), mMark(m
) {}
340 ~nsAutoPoolRelease() { JS_ARENA_RELEASE(mPool
, mMark
); }
346 // A utility function for script languages to call. Although it looks small,
347 // the use of nsIDocShell and nsPresContext triggers a huge number of
348 // dependencies that most languages would not otherwise need.
349 // XXXmarkh - This function is mis-placed!
351 NS_HandleScriptError(nsIScriptGlobalObject
*aScriptGlobal
,
352 nsScriptErrorEvent
*aErrorEvent
,
353 nsEventStatus
*aStatus
)
355 PRBool called
= PR_FALSE
;
356 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobal
));
357 nsIDocShell
*docShell
= win
? win
->GetDocShell() : nsnull
;
359 nsRefPtr
<nsPresContext
> presContext
;
360 docShell
->GetPresContext(getter_AddRefs(presContext
));
362 static PRInt32 errorDepth
; // Recursion prevention
365 if (presContext
&& errorDepth
< 2) {
366 // Dispatch() must be synchronous for the recursion block
367 // (errorDepth) to work.
368 nsEventDispatcher::Dispatch(win
, presContext
, aErrorEvent
, nsnull
,
377 class ScriptErrorEvent
: public nsRunnable
380 ScriptErrorEvent(nsIScriptGlobalObject
* aScriptGlobal
,
381 PRUint32 aLineNr
, PRUint32 aColumn
, PRUint32 aFlags
,
382 const nsAString
& aErrorMsg
,
383 const nsAString
& aFileName
,
384 const nsAString
& aSourceLine
,
385 PRBool aDispatchEvent
,
387 : mScriptGlobal(aScriptGlobal
), mLineNr(aLineNr
), mColumn(aColumn
),
388 mFlags(aFlags
), mErrorMsg(aErrorMsg
), mFileName(aFileName
),
389 mSourceLine(aSourceLine
), mDispatchEvent(aDispatchEvent
),
395 nsEventStatus status
= nsEventStatus_eIgnore
;
396 // First, notify the DOM that we have a script error.
397 if (mDispatchEvent
) {
398 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(mScriptGlobal
));
399 nsIDocShell
* docShell
= win
? win
->GetDocShell() : nsnull
;
401 !JSREPORT_IS_WARNING(mFlags
) &&
402 !sHandlingScriptError
) {
403 sHandlingScriptError
= PR_TRUE
; // Recursion prevention
405 nsRefPtr
<nsPresContext
> presContext
;
406 docShell
->GetPresContext(getter_AddRefs(presContext
));
409 nsScriptErrorEvent
errorevent(PR_TRUE
, NS_LOAD_ERROR
);
411 errorevent
.fileName
= mFileName
.get();
413 nsCOMPtr
<nsIScriptObjectPrincipal
> sop(do_QueryInterface(win
));
414 NS_ENSURE_STATE(sop
);
415 nsIPrincipal
* p
= sop
->GetPrincipal();
418 PRBool sameOrigin
= mFileName
.IsVoid();
420 if (p
&& !sameOrigin
) {
421 nsCOMPtr
<nsIURI
> errorURI
;
422 NS_NewURI(getter_AddRefs(errorURI
), mFileName
);
424 // FIXME: Once error reports contain the origin of the
425 // error (principals) we should change this to do the
426 // security check based on the principals and not
427 // URIs. See bug 387476.
428 sameOrigin
= NS_SUCCEEDED(p
->CheckMayLoad(errorURI
, PR_FALSE
));
432 NS_NAMED_LITERAL_STRING(xoriginMsg
, "Script error.");
434 errorevent
.errorMsg
= mErrorMsg
.get();
435 errorevent
.lineNr
= mLineNr
;
437 NS_WARNING("Not same origin error!");
438 errorevent
.errorMsg
= xoriginMsg
.get();
439 errorevent
.lineNr
= 0;
440 // FIXME: once the principal of the script is not tied to
441 // the filename, we can stop using the post-redirect
442 // filename if we want and remove this line. Note that
443 // apparently we can't handle null filenames in the error
444 // event dispatching code.
445 static PRUnichar nullFilename
[] = { PRUnichar(0) };
446 errorevent
.fileName
= nullFilename
;
449 nsEventDispatcher::Dispatch(win
, presContext
, &errorevent
, nsnull
,
453 sHandlingScriptError
= PR_FALSE
;
457 if (status
!= nsEventStatus_eConsumeNoDefault
) {
458 // Make an nsIScriptError and populate it with information from
460 nsCOMPtr
<nsIScriptError
> errorObject
=
461 do_CreateInstance("@mozilla.org/scripterror;1");
463 if (errorObject
!= nsnull
) {
464 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
466 // Set category to chrome or content
467 nsCOMPtr
<nsIScriptObjectPrincipal
> scriptPrincipal
=
468 do_QueryInterface(mScriptGlobal
);
469 NS_ASSERTION(scriptPrincipal
, "Global objects must implement "
470 "nsIScriptObjectPrincipal");
471 nsCOMPtr
<nsIPrincipal
> systemPrincipal
;
472 sSecurityManager
->GetSystemPrincipal(getter_AddRefs(systemPrincipal
));
473 const char * category
=
474 scriptPrincipal
->GetPrincipal() == systemPrincipal
475 ? "chrome javascript"
476 : "content javascript";
478 nsCOMPtr
<nsIScriptError2
> error2(do_QueryInterface(errorObject
));
480 rv
= error2
->InitWithWindowID(mErrorMsg
.get(), mFileName
.get(),
482 mLineNr
, mColumn
, mFlags
,
483 category
, mWindowID
);
485 rv
= errorObject
->Init(mErrorMsg
.get(), mFileName
.get(),
487 mLineNr
, mColumn
, mFlags
,
491 if (NS_SUCCEEDED(rv
)) {
492 nsCOMPtr
<nsIConsoleService
> consoleService
=
493 do_GetService(NS_CONSOLESERVICE_CONTRACTID
, &rv
);
494 if (NS_SUCCEEDED(rv
)) {
495 consoleService
->LogMessage(errorObject
);
504 nsCOMPtr
<nsIScriptGlobalObject
> mScriptGlobal
;
510 nsString mSourceLine
;
511 PRBool mDispatchEvent
;
514 static PRBool sHandlingScriptError
;
517 PRBool
ScriptErrorEvent::sHandlingScriptError
= PR_FALSE
;
519 // NOTE: This function could be refactored to use the above. The only reason
520 // it has not been done is that the code below only fills the error event
521 // after it has a good nsPresContext - whereas using the above function
522 // would involve always filling it. Is that a concern?
524 NS_ScriptErrorReporter(JSContext
*cx
,
526 JSErrorReport
*report
)
528 // We don't want to report exceptions too eagerly, but warnings in the
529 // absence of werror are swallowed whole, so report those now.
530 if (!JSREPORT_IS_WARNING(report
->flags
)) {
531 JSStackFrame
* fp
= nsnull
;
532 while ((fp
= JS_FrameIterator(cx
, &fp
))) {
533 if (JS_IsScriptFrame(cx
, fp
)) {
538 nsIXPConnect
* xpc
= nsContentUtils::XPConnect();
540 nsAXPCNativeCallContext
*cc
= nsnull
;
541 xpc
->GetCurrentNativeCallContext(&cc
);
543 nsAXPCNativeCallContext
*prev
= cc
;
544 while (NS_SUCCEEDED(prev
->GetPreviousCallContext(&prev
)) && prev
) {
546 if (NS_SUCCEEDED(prev
->GetLanguage(&lang
)) &&
547 lang
== nsAXPCNativeCallContext::LANG_JS
) {
555 // XXX this means we are not going to get error reports on non DOM contexts
556 nsIScriptContext
*context
= nsJSUtils::GetDynamicScriptContext(cx
);
558 // Note: we must do this before running any more code on cx (if cx is the
559 // dynamic script context).
560 ::JS_ClearPendingException(cx
);
563 nsIScriptGlobalObject
*globalObject
= context
->GetGlobalObject();
566 nsAutoString fileName
, msg
;
567 if (!report
->filename
) {
568 fileName
.SetIsVoid(PR_TRUE
);
570 fileName
.AssignWithConversion(report
->filename
);
573 const PRUnichar
*m
= reinterpret_cast<const PRUnichar
*>
579 if (msg
.IsEmpty() && message
) {
580 msg
.AssignWithConversion(message
);
584 /* We do not try to report Out Of Memory via a dom
585 * event because the dom event handler would encounter
586 * an OOM exception trying to process the event, and
587 * then we'd need to generate a new OOM event for that
588 * new OOM instance -- this isn't pretty.
590 nsAutoString sourceLine
;
591 sourceLine
.Assign(reinterpret_cast<const PRUnichar
*>(report
->uclinebuf
));
592 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(globalObject
);
593 PRUint64 windowID
= win
? win
->WindowID() : 0;
594 nsContentUtils::AddScriptRunner(
595 new ScriptErrorEvent(globalObject
, report
->lineno
,
596 report
->uctokenptr
- report
->uclinebuf
,
597 report
->flags
, msg
, fileName
, sourceLine
,
598 report
->errorNumber
!= JSMSG_OUT_OF_MEMORY
,
604 // Print it to stderr as well, for the benefit of those invoking
605 // mozilla with -console.
607 error
.Assign("JavaScript ");
608 if (JSREPORT_IS_STRICT(report
->flags
))
609 error
.Append("strict ");
610 if (JSREPORT_IS_WARNING(report
->flags
))
611 error
.Append("warning: ");
613 error
.Append("error: ");
614 error
.Append(report
->filename
);
615 error
.Append(", line ");
616 error
.AppendInt(report
->lineno
, 10);
618 if (report
->ucmessage
) {
619 AppendUTF16toUTF8(reinterpret_cast<const PRUnichar
*>(report
->ucmessage
),
622 error
.Append(message
);
625 fprintf(stderr
, "%s\n", error
.get());
631 gJSDiagnostics
= PR_NewLogModule("JSDiagnostics");
633 if (gJSDiagnostics
) {
634 PR_LOG(gJSDiagnostics
,
635 JSREPORT_IS_WARNING(report
->flags
) ? PR_LOG_WARNING
: PR_LOG_ERROR
,
636 ("file %s, line %u: %s\n%s%s",
637 report
->filename
, report
->lineno
, message
,
638 report
->linebuf
? report
->linebuf
: "",
640 report
->linebuf
[strlen(report
->linebuf
)-1] != '\n')
648 LocaleToUnicode(JSContext
*cx
, char *src
, jsval
*rval
)
653 // use app default locale
654 nsCOMPtr
<nsILocaleService
> localeService
=
655 do_GetService(NS_LOCALESERVICE_CONTRACTID
, &rv
);
656 if (NS_SUCCEEDED(rv
)) {
657 nsCOMPtr
<nsILocale
> appLocale
;
658 rv
= localeService
->GetApplicationLocale(getter_AddRefs(appLocale
));
659 if (NS_SUCCEEDED(rv
)) {
660 nsAutoString localeStr
;
662 GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME
), localeStr
);
663 NS_ASSERTION(NS_SUCCEEDED(rv
), "failed to get app locale info");
665 nsCOMPtr
<nsIPlatformCharset
> platformCharset
=
666 do_GetService(NS_PLATFORMCHARSET_CONTRACTID
, &rv
);
668 if (NS_SUCCEEDED(rv
)) {
669 nsCAutoString charset
;
670 rv
= platformCharset
->GetDefaultCharsetForLocale(localeStr
, charset
);
671 if (NS_SUCCEEDED(rv
)) {
672 // get/create unicode decoder for charset
673 nsCOMPtr
<nsICharsetConverterManager
> ccm
=
674 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID
, &rv
);
675 if (NS_SUCCEEDED(rv
))
676 ccm
->GetUnicodeDecoder(charset
.get(), &gDecoder
);
683 JSString
*str
= nsnull
;
684 PRInt32 srcLength
= PL_strlen(src
);
687 PRInt32 unicharLength
= srcLength
;
688 PRUnichar
*unichars
=
689 (PRUnichar
*)JS_malloc(cx
, (srcLength
+ 1) * sizeof(PRUnichar
));
691 rv
= gDecoder
->Convert(src
, &srcLength
, unichars
, &unicharLength
);
692 if (NS_SUCCEEDED(rv
)) {
693 // terminate the returned string
694 unichars
[unicharLength
] = 0;
696 // nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
697 if (unicharLength
+ 1 < srcLength
+ 1) {
698 PRUnichar
*shrunkUnichars
=
699 (PRUnichar
*)JS_realloc(cx
, unichars
,
700 (unicharLength
+ 1) * sizeof(PRUnichar
));
702 unichars
= shrunkUnichars
;
704 str
= JS_NewUCString(cx
,
705 reinterpret_cast<jschar
*>(unichars
),
709 JS_free(cx
, unichars
);
714 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_OUT_OF_MEMORY
);
718 *rval
= STRING_TO_JSVAL(str
);
724 ChangeCase(JSContext
*cx
, JSString
*src
, jsval
*rval
,
725 void(* changeCaseFnc
)(const nsAString
&, nsAString
&))
728 changeCaseFnc(nsDependentJSString(src
), result
);
730 JSString
*ucstr
= JS_NewUCStringCopyN(cx
, (jschar
*)result
.get(), result
.Length());
735 *rval
= STRING_TO_JSVAL(ucstr
);
741 LocaleToUpperCase(JSContext
*cx
, JSString
*src
, jsval
*rval
)
743 return ChangeCase(cx
, src
, rval
, ToUpperCase
);
747 LocaleToLowerCase(JSContext
*cx
, JSString
*src
, jsval
*rval
)
749 return ChangeCase(cx
, src
, rval
, ToLowerCase
);
753 LocaleCompare(JSContext
*cx
, JSString
*src1
, JSString
*src2
, jsval
*rval
)
758 nsCOMPtr
<nsILocaleService
> localeService
=
759 do_GetService(NS_LOCALESERVICE_CONTRACTID
, &rv
);
761 if (NS_SUCCEEDED(rv
)) {
762 nsCOMPtr
<nsILocale
> locale
;
763 rv
= localeService
->GetApplicationLocale(getter_AddRefs(locale
));
765 if (NS_SUCCEEDED(rv
)) {
766 nsCOMPtr
<nsICollationFactory
> colFactory
=
767 do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID
, &rv
);
769 if (NS_SUCCEEDED(rv
)) {
770 rv
= colFactory
->CreateCollation(locale
, &gCollation
);
776 nsDOMClassInfo::ThrowJSException(cx
, rv
);
783 rv
= gCollation
->CompareString(nsICollation::kCollationStrengthDefault
,
784 nsDependentJSString(src1
),
785 nsDependentJSString(src2
),
789 nsDOMClassInfo::ThrowJSException(cx
, rv
);
794 *rval
= INT_TO_JSVAL(result
);
800 // A couple of useful functions to call when you're debugging.
802 JSObject2Win(JSContext
*cx
, JSObject
*obj
)
804 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
809 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
810 xpc
->GetWrappedNativeOfJSObject(cx
, obj
, getter_AddRefs(wrapper
));
812 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryWrappedNative(wrapper
);
814 return static_cast<nsGlobalWindow
*>
815 (static_cast<nsPIDOMWindow
*>(win
));
823 PrintWinURI(nsGlobalWindow
*win
)
826 printf("No window passed in.\n");
830 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(win
->GetExtantDocument());
832 printf("No document in the window.\n");
836 nsIURI
*uri
= doc
->GetDocumentURI();
838 printf("Document doesn't have a URI.\n");
844 printf("%s\n", spec
.get());
848 PrintWinCodebase(nsGlobalWindow
*win
)
851 printf("No window passed in.\n");
855 nsIPrincipal
*prin
= win
->GetPrincipal();
857 printf("Window doesn't have principals.\n");
861 nsCOMPtr
<nsIURI
> uri
;
862 prin
->GetURI(getter_AddRefs(uri
));
864 printf("No URI, maybe the system principal.\n");
870 printf("%s\n", spec
.get());
874 DumpString(const nsAString
&str
)
876 printf("%s\n", NS_ConvertUTF16toUTF8(str
).get());
881 MaybeGC(JSContext
*cx
)
883 size_t bytes
= cx
->runtime
->gcBytes
;
884 size_t lastBytes
= cx
->runtime
->gcLastBytes
;
885 if ((bytes
> 8192 && bytes
> lastBytes
* 16)
887 || cx
->runtime
->gcZeal
> 0
894 static already_AddRefed
<nsIPrompt
>
895 GetPromptFromContext(nsJSContext
* ctx
)
897 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(ctx
->GetGlobalObject()));
898 NS_ENSURE_TRUE(win
, nsnull
);
900 nsIDocShell
*docShell
= win
->GetDocShell();
901 NS_ENSURE_TRUE(docShell
, nsnull
);
903 nsCOMPtr
<nsIInterfaceRequestor
> ireq(do_QueryInterface(docShell
));
904 NS_ENSURE_TRUE(ireq
, nsnull
);
906 // Get the nsIPrompt interface from the docshell
908 ireq
->GetInterface(NS_GET_IID(nsIPrompt
), (void**)&prompt
);
913 nsJSContext::DOMOperationCallback(JSContext
*cx
)
917 // Get the native context
918 nsJSContext
*ctx
= static_cast<nsJSContext
*>(::JS_GetContextPrivate(cx
));
921 // Can happen; see bug 355811
925 // XXX Save the operation callback time so we can restore it after the GC,
926 // because GCing can cause JS to run on our context, causing our
927 // ScriptEvaluated to be called, and clearing our operation callback time.
929 PRTime callbackTime
= ctx
->mOperationCallbackTime
;
930 PRTime modalStateTime
= ctx
->mModalStateTime
;
934 // Now restore the callback time and count, in case they got reset.
935 ctx
->mOperationCallbackTime
= callbackTime
;
936 ctx
->mModalStateTime
= modalStateTime
;
938 PRTime now
= PR_Now();
940 if (callbackTime
== 0) {
941 // Initialize mOperationCallbackTime to start timing how long the
943 ctx
->mOperationCallbackTime
= now
;
947 if (ctx
->mModalStateDepth
) {
948 // We're waiting on a modal dialog, nothing more to do here.
952 PRTime duration
= now
- callbackTime
;
954 // Check the amount of time this script has been running, or if the
955 // dialog is disabled.
956 JSObject
* global
= ::JS_GetGlobalForScopeChain(cx
);
957 PRBool isTrackingChromeCodeTime
=
958 global
&& xpc::AccessCheck::isChrome(global
->getCompartment());
959 if (duration
< (isTrackingChromeCodeTime
?
960 sMaxChromeScriptRunTime
: sMaxScriptRunTime
)) {
964 if (!nsContentUtils::IsSafeToRunScript()) {
965 // If it isn't safe to run script, then it isn't safe to bring up the
966 // prompt (since that will cause the event loop to spin). In this case
967 // (which is rare), we just stop the script... But report a warning so
968 // that developers have some idea of what went wrong.
970 JS_ReportWarning(cx
, "A long running script was terminated");
974 // If we get here we're most likely executing an infinite loop in JS,
975 // we'll tell the user about this and we'll give the user the option
976 // of stopping the execution of the script.
977 nsCOMPtr
<nsIPrompt
> prompt
= GetPromptFromContext(ctx
);
978 NS_ENSURE_TRUE(prompt
, JS_TRUE
);
980 // Check if we should offer the option to debug
981 JSStackFrame
* fp
= ::JS_GetScriptedCaller(cx
, NULL
);
982 PRBool debugPossible
= (fp
!= nsnull
&& cx
->debugHooks
&&
983 cx
->debugHooks
->debuggerHandler
!= nsnull
);
984 #ifdef MOZ_JSDEBUGGER
985 // Get the debugger service if necessary.
987 PRBool jsds_IsOn
= PR_FALSE
;
988 const char jsdServiceCtrID
[] = "@mozilla.org/js/jsd/debugger-service;1";
989 nsCOMPtr
<jsdIExecutionHook
> jsdHook
;
990 nsCOMPtr
<jsdIDebuggerService
> jsds
= do_GetService(jsdServiceCtrID
, &rv
);
992 // Check if there's a user for the debugger service that's 'on' for us
993 if (NS_SUCCEEDED(rv
)) {
994 jsds
->GetDebuggerHook(getter_AddRefs(jsdHook
));
995 jsds
->GetIsOn(&jsds_IsOn
);
998 // If there is a debug handler registered for this runtime AND
999 // ((jsd is on AND has a hook) OR (jsd isn't on (something else debugs)))
1000 // then something useful will be done with our request to debug.
1001 debugPossible
= ((jsds_IsOn
&& (jsdHook
!= nsnull
)) || !jsds_IsOn
);
1005 // Get localizable strings
1006 nsXPIDLString title
, msg
, stopButton
, waitButton
, debugButton
, neverShowDlg
;
1008 rv
= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1012 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1016 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1017 "WaitForScriptButton",
1020 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1025 if (debugPossible
) {
1026 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1027 "DebugScriptButton",
1030 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1031 "KillScriptWithDebugMessage",
1035 rv
|= nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1036 "KillScriptMessage",
1040 //GetStringFromName can return NS_OK and still give NULL string
1041 if (NS_FAILED(rv
) || !title
|| !msg
|| !stopButton
|| !waitButton
||
1042 (!debugButton
&& debugPossible
) || !neverShowDlg
) {
1043 NS_ERROR("Failed to get localized strings.");
1047 // Append file and line number information, if available
1048 JSScript
*script
= fp
? ::JS_GetFrameScript(cx
, fp
) : nsnull
;
1050 const char *filename
= ::JS_GetScriptFilename(cx
, script
);
1052 nsXPIDLString scriptLocation
;
1053 NS_ConvertUTF8toUTF16
filenameUTF16(filename
);
1054 const PRUnichar
*formatParams
[] = { filenameUTF16
.get() };
1055 rv
= nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES
,
1056 "KillScriptLocation",
1060 if (NS_SUCCEEDED(rv
) && scriptLocation
) {
1061 msg
.AppendLiteral("\n\n");
1062 msg
.Append(scriptLocation
);
1064 JSStackFrame
*fp
, *iterator
= nsnull
;
1065 fp
= ::JS_FrameIterator(cx
, &iterator
);
1067 jsbytecode
*pc
= ::JS_GetFramePC(cx
, fp
);
1069 PRUint32 lineno
= ::JS_PCToLineNumber(cx
, script
, pc
);
1071 msg
.AppendInt(lineno
);
1078 PRInt32 buttonPressed
= 0; //In case user exits dialog by clicking X
1079 PRBool neverShowDlgChk
= PR_FALSE
;
1080 PRUint32 buttonFlags
= nsIPrompt::BUTTON_POS_1_DEFAULT
+
1081 (nsIPrompt::BUTTON_TITLE_IS_STRING
*
1082 (nsIPrompt::BUTTON_POS_0
+ nsIPrompt::BUTTON_POS_1
));
1084 // Add a third button if necessary:
1086 buttonFlags
+= nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_2
;
1088 // Null out the operation callback while we're re-entering JS here.
1089 ::JS_SetOperationCallback(cx
, nsnull
);
1092 rv
= prompt
->ConfirmEx(title
, msg
, buttonFlags
, waitButton
, stopButton
,
1093 debugButton
, neverShowDlg
, &neverShowDlgChk
,
1096 ::JS_SetOperationCallback(cx
, DOMOperationCallback
);
1098 if (NS_FAILED(rv
) || (buttonPressed
== 0)) {
1099 // Allow the script to continue running
1101 if (neverShowDlgChk
) {
1102 nsIPrefBranch
*prefBranch
= nsContentUtils::GetPrefBranch();
1105 prefBranch
->SetIntPref(isTrackingChromeCodeTime
?
1106 "dom.max_chrome_script_run_time" :
1107 "dom.max_script_run_time", 0);
1111 ctx
->mOperationCallbackTime
= PR_Now();
1114 else if ((buttonPressed
== 2) && debugPossible
) {
1117 switch(cx
->debugHooks
->debuggerHandler(cx
, script
, ::JS_GetFramePC(cx
, fp
),
1120 debuggerHandlerData
)) {
1122 JS_SetFrameReturnValue(cx
, fp
, rval
);
1125 cx
->throwing
= JS_FALSE
;
1128 JS_SetPendingException(cx
, rval
);
1130 case JSTRAP_CONTINUE
:
1136 JS_ClearPendingException(cx
);
1141 nsJSContext::EnterModalState()
1143 if (!mModalStateDepth
) {
1144 mModalStateTime
= mOperationCallbackTime
? PR_Now() : 0;
1150 nsJSContext::LeaveModalState()
1152 if (!mModalStateDepth
) {
1153 NS_ERROR("Uh, mismatched LeaveModalState() call!");
1160 // If we're still in a modal dialog, or mOperationCallbackTime is still
1161 // uninitialized, do nothing.
1162 if (mModalStateDepth
|| !mOperationCallbackTime
) {
1166 // If mOperationCallbackTime was set when we entered the first dialog
1167 // (and mModalStateTime is thus non-zero), adjust mOperationCallbackTime
1168 // to account for time spent in the dialog.
1169 // If mOperationCallbackTime got set while the modal dialog was open,
1170 // simply set mOperationCallbackTime to the closing time of the dialog so
1171 // that we never adjust mOperationCallbackTime to be in the future.
1172 if (mModalStateTime
) {
1173 mOperationCallbackTime
+= PR_Now() - mModalStateTime
;
1176 mOperationCallbackTime
= PR_Now();
1180 #define JS_OPTIONS_DOT_STR "javascript.options."
1182 static const char js_options_dot_str
[] = JS_OPTIONS_DOT_STR
;
1183 static const char js_strict_option_str
[] = JS_OPTIONS_DOT_STR
"strict";
1185 static const char js_strict_debug_option_str
[] = JS_OPTIONS_DOT_STR
"strict.debug";
1187 static const char js_werror_option_str
[] = JS_OPTIONS_DOT_STR
"werror";
1188 static const char js_relimit_option_str
[]= JS_OPTIONS_DOT_STR
"relimit";
1190 static const char js_zeal_option_str
[] = JS_OPTIONS_DOT_STR
"gczeal";
1192 static const char js_tracejit_content_str
[] = JS_OPTIONS_DOT_STR
"tracejit.content";
1193 static const char js_tracejit_chrome_str
[] = JS_OPTIONS_DOT_STR
"tracejit.chrome";
1194 static const char js_methodjit_content_str
[] = JS_OPTIONS_DOT_STR
"methodjit.content";
1195 static const char js_methodjit_chrome_str
[] = JS_OPTIONS_DOT_STR
"methodjit.chrome";
1196 static const char js_profiling_content_str
[] = JS_OPTIONS_DOT_STR
"jitprofiling.content";
1197 static const char js_profiling_chrome_str
[] = JS_OPTIONS_DOT_STR
"jitprofiling.chrome";
1200 nsJSContext::JSOptionChangedCallback(const char *pref
, void *data
)
1202 nsJSContext
*context
= reinterpret_cast<nsJSContext
*>(data
);
1203 PRUint32 oldDefaultJSOptions
= context
->mDefaultJSOptions
;
1204 PRUint32 newDefaultJSOptions
= oldDefaultJSOptions
;
1206 PRBool strict
= nsContentUtils::GetBoolPref(js_strict_option_str
);
1208 newDefaultJSOptions
|= JSOPTION_STRICT
;
1210 newDefaultJSOptions
&= ~JSOPTION_STRICT
;
1212 nsIScriptGlobalObject
*global
= context
->GetGlobalObject();
1213 // XXX should we check for sysprin instead of a chrome window, to make
1214 // XXX components be covered by the chrome pref instead of the content one?
1215 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(global
));
1217 PRBool useTraceJIT
= nsContentUtils::GetBoolPref(chromeWindow
?
1218 js_tracejit_chrome_str
:
1219 js_tracejit_content_str
);
1220 PRBool useMethodJIT
= nsContentUtils::GetBoolPref(chromeWindow
?
1221 js_methodjit_chrome_str
:
1222 js_methodjit_content_str
);
1223 PRBool useProfiling
= nsContentUtils::GetBoolPref(chromeWindow
?
1224 js_profiling_chrome_str
:
1225 js_profiling_content_str
);
1226 nsCOMPtr
<nsIXULRuntime
> xr
= do_GetService(XULRUNTIME_SERVICE_CONTRACTID
);
1228 PRBool safeMode
= PR_FALSE
;
1229 xr
->GetInSafeMode(&safeMode
);
1231 useTraceJIT
= PR_FALSE
;
1232 useMethodJIT
= PR_FALSE
;
1233 useProfiling
= PR_FALSE
;
1238 newDefaultJSOptions
|= JSOPTION_JIT
;
1240 newDefaultJSOptions
&= ~JSOPTION_JIT
;
1243 newDefaultJSOptions
|= JSOPTION_METHODJIT
;
1245 newDefaultJSOptions
&= ~JSOPTION_METHODJIT
;
1248 newDefaultJSOptions
|= JSOPTION_PROFILING
;
1250 newDefaultJSOptions
&= ~JSOPTION_PROFILING
;
1253 // In debug builds, warnings are enabled in chrome context if javascript.options.strict.debug is true
1254 PRBool strictDebug
= nsContentUtils::GetBoolPref(js_strict_debug_option_str
);
1255 // Note this callback is also called from context's InitClasses thus we don't
1256 // need to enable this directly from InitContext
1257 if (strictDebug
&& (newDefaultJSOptions
& JSOPTION_STRICT
) == 0) {
1259 newDefaultJSOptions
|= JSOPTION_STRICT
;
1263 PRBool werror
= nsContentUtils::GetBoolPref(js_werror_option_str
);
1265 newDefaultJSOptions
|= JSOPTION_WERROR
;
1267 newDefaultJSOptions
&= ~JSOPTION_WERROR
;
1269 PRBool relimit
= nsContentUtils::GetBoolPref(js_relimit_option_str
);
1271 newDefaultJSOptions
|= JSOPTION_RELIMIT
;
1273 newDefaultJSOptions
&= ~JSOPTION_RELIMIT
;
1275 if (newDefaultJSOptions
!= oldDefaultJSOptions
) {
1276 // Set options only if we used the old defaults; otherwise the page has
1277 // customized some via the options object and we defer to its wisdom.
1278 if (::JS_GetOptions(context
->mContext
) == oldDefaultJSOptions
)
1279 ::JS_SetOptions(context
->mContext
, newDefaultJSOptions
);
1281 // Save the new defaults for the next page load (InitContext).
1282 context
->mDefaultJSOptions
= newDefaultJSOptions
;
1286 PRInt32 zeal
= nsContentUtils::GetIntPref(js_zeal_option_str
, -1);
1288 ::JS_SetGCZeal(context
->mContext
, (PRUint8
)zeal
);
1294 nsJSContext::nsJSContext(JSRuntime
*aRuntime
)
1295 : mGCOnDestruction(PR_TRUE
),
1301 mDefaultJSOptions
= JSOPTION_PRIVATE_IS_NSISUPPORTS
| JSOPTION_ANONFUNFIX
;
1303 mContext
= ::JS_NewContext(aRuntime
, gStackSize
);
1305 ::JS_SetContextPrivate(mContext
, static_cast<nsIScriptContext
*>(this));
1307 // Preserve any flags the context callback might have set.
1308 mDefaultJSOptions
|= ::JS_GetOptions(mContext
);
1310 // Make sure the new context gets the default context options
1311 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
1313 // Watch for the JS boolean options
1314 nsContentUtils::RegisterPrefCallback(js_options_dot_str
,
1315 JSOptionChangedCallback
,
1318 ::JS_SetOperationCallback(mContext
, DOMOperationCallback
);
1320 static JSLocaleCallbacks localeCallbacks
=
1328 ::JS_SetLocaleCallbacks(mContext
, &localeCallbacks
);
1330 mIsInitialized
= PR_FALSE
;
1331 mNumEvaluations
= 0;
1332 mTerminations
= nsnull
;
1333 mScriptsEnabled
= PR_TRUE
;
1334 mOperationCallbackTime
= 0;
1335 mModalStateTime
= 0;
1336 mModalStateDepth
= 0;
1337 mProcessingScriptTag
= PR_FALSE
;
1340 nsJSContext::~nsJSContext()
1343 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptContext
*>(this));
1345 NS_PRECONDITION(!mTerminations
, "Shouldn't have termination funcs by now");
1347 mGlobalObjectRef
= nsnull
;
1353 if (!sContextCount
&& sDidShutdown
) {
1354 // The last context is being deleted, and we're already in the
1355 // process of shutting down, release the JS runtime service, and
1356 // the security manager.
1358 NS_IF_RELEASE(sRuntimeService
);
1359 NS_IF_RELEASE(sSecurityManager
);
1360 NS_IF_RELEASE(gCollation
);
1361 NS_IF_RELEASE(gDecoder
);
1366 nsJSContext::DestroyJSContext()
1371 // Clear our entry in the JSContext, bugzilla bug 66413
1372 ::JS_SetContextPrivate(mContext
, nsnull
);
1374 // Unregister our "javascript.options.*" pref-changed callback.
1375 nsContentUtils::UnregisterPrefCallback(js_options_dot_str
,
1376 JSOptionChangedCallback
,
1379 PRBool do_gc
= mGCOnDestruction
&& !sGCTimer
&& sReadyForGC
;
1381 // Let xpconnect destroy the JSContext when it thinks the time is right.
1382 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
1384 xpc
->ReleaseJSContext(mContext
, !do_gc
);
1386 ::JS_DestroyContext(mContext
);
1388 ::JS_DestroyContextNoGC(mContext
);
1393 // QueryInterface implementation for nsJSContext
1394 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSContext
)
1395 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSContext
)
1396 NS_ASSERTION(!tmp
->mContext
|| tmp
->mContext
->outstandingRequests
== 0,
1397 "Trying to unlink a context with outstanding requests.");
1398 tmp
->mIsInitialized
= PR_FALSE
;
1399 tmp
->mGCOnDestruction
= PR_FALSE
;
1400 tmp
->DestroyJSContext();
1401 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1402 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSContext
)
1403 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1404 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSContext
)
1405 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGlobalObjectRef
)
1406 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1407 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSContext
)
1408 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSContext
, tmp
->GetCCRefcnt())
1409 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGlobalObjectRef
)
1410 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mContext");
1411 nsContentUtils::XPConnect()->NoteJSContext(tmp
->mContext
, cb
);
1412 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1414 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSContext
)
1415 NS_INTERFACE_MAP_ENTRY(nsIScriptContext
)
1416 NS_INTERFACE_MAP_ENTRY(nsIScriptContextPrincipal
)
1417 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptNotify
)
1418 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIScriptContext
)
1419 NS_INTERFACE_MAP_END
1422 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSContext
, nsIScriptContext
)
1423 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSContext
, nsIScriptContext
)
1426 nsJSContext::GetCCRefcnt()
1428 nsrefcnt refcnt
= mRefCnt
.get();
1429 if (NS_LIKELY(mContext
))
1430 refcnt
+= mContext
->outstandingRequests
;
1435 nsJSContext::EvaluateStringWithValue(const nsAString
& aScript
,
1437 nsIPrincipal
*aPrincipal
,
1442 PRBool
* aIsUndefined
)
1444 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1445 __LINE__
, aURL
, aLineNo
);
1447 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1449 if (!mScriptsEnabled
) {
1451 *aIsUndefined
= PR_TRUE
;
1459 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1461 // Safety first: get an object representing the script's principals, i.e.,
1462 // the entities who signed this script, or the fully-qualified-domain-name
1463 // or "codebase" from which it was loaded.
1464 JSPrincipals
*jsprin
;
1465 nsIPrincipal
*principal
= aPrincipal
;
1467 nsIScriptGlobalObject
*global
= GetGlobalObject();
1469 return NS_ERROR_FAILURE
;
1470 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
1471 do_QueryInterface(global
, &rv
);
1473 return NS_ERROR_FAILURE
;
1474 principal
= objPrincipal
->GetPrincipal();
1476 return NS_ERROR_FAILURE
;
1479 principal
->GetJSPrincipals(mContext
, &jsprin
);
1481 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1483 PRBool ok
= PR_FALSE
;
1485 rv
= sSecurityManager
->CanExecuteScripts(mContext
, principal
, &ok
);
1486 if (NS_FAILED(rv
)) {
1487 JSPRINCIPALS_DROP(mContext
, jsprin
);
1488 return NS_ERROR_FAILURE
;
1491 // Push our JSContext on the current thread's context stack so JS called
1492 // from native code via XPConnect uses the right context. Do this whether
1493 // or not the SecurityManager said "ok", in order to simplify control flow
1494 // below where we pop before returning.
1495 nsCOMPtr
<nsIJSContextStack
> stack
=
1496 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1497 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1498 JSPRINCIPALS_DROP(mContext
, jsprin
);
1499 return NS_ERROR_FAILURE
;
1504 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1505 NS_ENSURE_SUCCESS(rv
, rv
);
1507 nsJSContext::TerminationFuncHolder
holder(this);
1509 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1510 // Since the caller is responsible for parsing the version strings, we just
1511 // check it isn't JSVERSION_UNKNOWN.
1512 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1514 JSAutoRequest
ar(mContext
);
1516 JSAutoEnterCompartment ac
;
1517 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1518 JSPRINCIPALS_DROP(mContext
, jsprin
);
1520 return NS_ERROR_FAILURE
;
1525 ok
= ::JS_EvaluateUCScriptForPrincipalsVersion(mContext
,
1526 (JSObject
*)aScopeObject
,
1528 (jschar
*)PromiseFlatString(aScript
).get(),
1533 JSVersion(aVersion
));
1538 // Tell XPConnect about any pending exceptions. This is needed
1539 // to avoid dropping JS exceptions in case we got here through
1540 // nested calls through XPConnect.
1542 ReportPendingException();
1546 // Whew! Finally done with these manually ref-counted things.
1547 JSPRINCIPALS_DROP(mContext
, jsprin
);
1549 // If all went well, convert val to a string (XXXbe unless undefined?).
1552 *aIsUndefined
= JSVAL_IS_VOID(val
);
1555 *static_cast<jsval
*>(aRetValue
) = val
;
1556 // XXX - nsScriptObjectHolder should be used once this method moves to
1557 // the new world order. However, use of 'jsval' appears to make this
1562 *aIsUndefined
= PR_TRUE
;
1566 sSecurityManager
->PopContextPrincipal(mContext
);
1568 // Pop here, after JS_ValueToString and any other possible evaluation.
1569 if (NS_FAILED(stack
->Pop(nsnull
)))
1570 rv
= NS_ERROR_FAILURE
;
1572 // ScriptEvaluated needs to come after we pop the stack
1573 ScriptEvaluated(PR_TRUE
);
1579 // Helper function to convert a jsval to an nsAString, and set
1580 // exception flags if the conversion fails.
1582 JSValueToAString(JSContext
*cx
, jsval val
, nsAString
*result
,
1583 PRBool
*isUndefined
)
1586 *isUndefined
= JSVAL_IS_VOID(val
);
1593 JSString
* jsstring
= ::JS_ValueToString(cx
, val
);
1595 result
->Assign(reinterpret_cast<const PRUnichar
*>
1596 (::JS_GetStringChars(jsstring
)),
1597 ::JS_GetStringLength(jsstring
));
1601 // We failed to convert val to a string. We're either OOM, or the
1602 // security manager denied access to .toString(), or somesuch, on
1603 // an object. Treat this case as if the result were undefined.
1606 *isUndefined
= PR_TRUE
;
1609 if (!::JS_IsExceptionPending(cx
)) {
1610 // JS_ValueToString() returned null w/o an exception
1611 // pending. That means we're OOM.
1613 return NS_ERROR_OUT_OF_MEMORY
;
1620 nsIScriptObjectPrincipal
*
1621 nsJSContext::GetObjectPrincipal()
1623 nsCOMPtr
<nsIScriptObjectPrincipal
> prin
= do_QueryInterface(GetGlobalObject());
1628 nsJSContext::EvaluateString(const nsAString
& aScript
,
1630 nsIPrincipal
*aPrincipal
,
1634 nsAString
*aRetValue
,
1635 PRBool
* aIsUndefined
)
1637 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1638 __LINE__
, aURL
, aLineNo
);
1640 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1642 if (!mScriptsEnabled
) {
1644 *aIsUndefined
= PR_TRUE
;
1648 aRetValue
->Truncate();
1656 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1658 // Safety first: get an object representing the script's principals, i.e.,
1659 // the entities who signed this script, or the fully-qualified-domain-name
1660 // or "codebase" from which it was loaded.
1661 JSPrincipals
*jsprin
;
1662 nsIPrincipal
*principal
= aPrincipal
;
1664 aPrincipal
->GetJSPrincipals(mContext
, &jsprin
);
1667 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrincipal
=
1668 do_QueryInterface(GetGlobalObject(), &rv
);
1670 return NS_ERROR_FAILURE
;
1671 principal
= objPrincipal
->GetPrincipal();
1673 return NS_ERROR_FAILURE
;
1674 principal
->GetJSPrincipals(mContext
, &jsprin
);
1677 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1679 PRBool ok
= PR_FALSE
;
1681 rv
= sSecurityManager
->CanExecuteScripts(mContext
, principal
, &ok
);
1682 if (NS_FAILED(rv
)) {
1683 JSPRINCIPALS_DROP(mContext
, jsprin
);
1684 return NS_ERROR_FAILURE
;
1687 // Push our JSContext on the current thread's context stack so JS called
1688 // from native code via XPConnect uses the right context. Do this whether
1689 // or not the SecurityManager said "ok", in order to simplify control flow
1690 // below where we pop before returning.
1691 nsCOMPtr
<nsIJSContextStack
> stack
=
1692 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1693 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1694 JSPRINCIPALS_DROP(mContext
, jsprin
);
1695 return NS_ERROR_FAILURE
;
1698 // The result of evaluation, used only if there were no errors. This need
1699 // not be a GC root currently, provided we run the GC only from the
1700 // operation callback or from ScriptEvaluated.
1701 jsval val
= JSVAL_VOID
;
1702 jsval
* vp
= aRetValue
? &val
: NULL
;
1704 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1705 NS_ENSURE_SUCCESS(rv
, rv
);
1707 nsJSContext::TerminationFuncHolder
holder(this);
1711 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1712 // Since the caller is responsible for parsing the version strings, we just
1713 // check it isn't JSVERSION_UNKNOWN.
1714 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1715 JSAutoRequest
ar(mContext
);
1716 JSAutoEnterCompartment ac
;
1717 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1719 JSPRINCIPALS_DROP(mContext
, jsprin
);
1720 return NS_ERROR_FAILURE
;
1723 ok
= ::JS_EvaluateUCScriptForPrincipalsVersion(mContext
,
1724 (JSObject
*)aScopeObject
,
1726 (jschar
*)PromiseFlatString(aScript
).get(),
1731 JSVersion(aVersion
));
1734 // Tell XPConnect about any pending exceptions. This is needed
1735 // to avoid dropping JS exceptions in case we got here through
1736 // nested calls through XPConnect.
1738 ReportPendingException();
1742 // Whew! Finally done with these manually ref-counted things.
1743 JSPRINCIPALS_DROP(mContext
, jsprin
);
1745 // If all went well, convert val to a string if one is wanted.
1747 JSAutoRequest
ar(mContext
);
1748 JSAutoEnterCompartment ac
;
1749 if (!ac
.enter(mContext
, (JSObject
*)aScopeObject
)) {
1752 rv
= JSValueToAString(mContext
, val
, aRetValue
, aIsUndefined
);
1756 *aIsUndefined
= PR_TRUE
;
1760 aRetValue
->Truncate();
1766 sSecurityManager
->PopContextPrincipal(mContext
);
1768 // Pop here, after JS_ValueToString and any other possible evaluation.
1769 if (NS_FAILED(stack
->Pop(nsnull
)))
1770 rv
= NS_ERROR_FAILURE
;
1772 // ScriptEvaluated needs to come after we pop the stack
1773 ScriptEvaluated(PR_TRUE
);
1779 nsJSContext::CompileScript(const PRUnichar
* aText
,
1780 PRInt32 aTextLength
,
1782 nsIPrincipal
*aPrincipal
,
1786 nsScriptObjectHolder
&aScriptObject
)
1788 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1791 NS_ENSURE_ARG_POINTER(aPrincipal
);
1794 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1796 JSPrincipals
*jsprin
;
1797 aPrincipal
->GetJSPrincipals(mContext
, &jsprin
);
1798 // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
1800 PRBool ok
= PR_FALSE
;
1802 rv
= sSecurityManager
->CanExecuteScripts(mContext
, aPrincipal
, &ok
);
1803 if (NS_FAILED(rv
)) {
1804 JSPRINCIPALS_DROP(mContext
, jsprin
);
1805 return NS_ERROR_FAILURE
;
1808 aScriptObject
.drop(); // ensure old object not used on failure...
1810 // SecurityManager said "ok", but don't compile if aVersion is unknown.
1811 // Since the caller is responsible for parsing the version strings, we just
1812 // check it isn't JSVERSION_UNKNOWN.
1813 if (ok
&& ((JSVersion
)aVersion
) != JSVERSION_UNKNOWN
) {
1814 JSAutoRequest
ar(mContext
);
1817 ::JS_CompileUCScriptForPrincipalsVersion(mContext
,
1818 (JSObject
*)aScopeObject
,
1824 JSVersion(aVersion
));
1826 JSObject
*scriptObject
= ::JS_NewScriptObject(mContext
, script
);
1828 NS_ASSERTION(aScriptObject
.getScriptTypeID()==JAVASCRIPT
,
1829 "Expecting JS script object holder");
1830 rv
= aScriptObject
.set(scriptObject
);
1832 ::JS_DestroyScript(mContext
, script
);
1836 rv
= NS_ERROR_OUT_OF_MEMORY
;
1840 // Whew! Finally done.
1841 JSPRINCIPALS_DROP(mContext
, jsprin
);
1846 nsJSContext::ExecuteScript(void *aScriptObject
,
1848 nsAString
* aRetValue
,
1849 PRBool
* aIsUndefined
)
1851 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1853 if (!mScriptsEnabled
) {
1855 *aIsUndefined
= PR_TRUE
;
1859 aRetValue
->Truncate();
1868 aScopeObject
= ::JS_GetGlobalObject(mContext
);
1870 // Push our JSContext on our thread's context stack, in case native code
1871 // called from JS calls back into JS via XPConnect.
1872 nsCOMPtr
<nsIJSContextStack
> stack
=
1873 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1874 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
1875 return NS_ERROR_FAILURE
;
1878 // The result of evaluation, used only if there were no errors. This need
1879 // not be a GC root currently, provided we run the GC only from the
1880 // operation callback or from ScriptEvaluated.
1884 JSObject
*scriptObj
= (JSObject
*)aScriptObject
;
1885 nsCOMPtr
<nsIPrincipal
> principal
;
1887 rv
= sSecurityManager
->GetObjectPrincipal(mContext
, scriptObj
, getter_AddRefs(principal
));
1888 NS_ENSURE_SUCCESS(rv
, rv
);
1890 rv
= sSecurityManager
->PushContextPrincipal(mContext
, nsnull
, principal
);
1891 NS_ENSURE_SUCCESS(rv
, rv
);
1893 nsJSContext::TerminationFuncHolder
holder(this);
1894 JSAutoRequest
ar(mContext
);
1896 ok
= ::JS_ExecuteScript(mContext
,
1897 (JSObject
*)aScopeObject
,
1898 (JSScript
*)::JS_GetPrivate(mContext
, scriptObj
),
1902 // If all went well, convert val to a string (XXXbe unless undefined?).
1903 rv
= JSValueToAString(mContext
, val
, aRetValue
, aIsUndefined
);
1906 *aIsUndefined
= PR_TRUE
;
1910 aRetValue
->Truncate();
1916 sSecurityManager
->PopContextPrincipal(mContext
);
1918 // Pop here, after JS_ValueToString and any other possible evaluation.
1919 if (NS_FAILED(stack
->Pop(nsnull
)))
1920 rv
= NS_ERROR_FAILURE
;
1922 // ScriptEvaluated needs to come after we pop the stack
1923 ScriptEvaluated(PR_TRUE
);
1931 AtomIsEventHandlerName(nsIAtom
*aName
)
1933 const PRUnichar
*name
= aName
->GetUTF16String();
1935 const PRUnichar
*cp
;
1937 for (cp
= name
; *cp
!= '\0'; ++cp
)
1940 if ((c
< 'A' || c
> 'Z') && (c
< 'a' || c
> 'z'))
1948 // Helper function to find the JSObject associated with a (presumably DOM)
1951 nsJSContext::JSObjectFromInterface(nsISupports
* aTarget
, void *aScope
, JSObject
**aRet
)
1953 // It is legal to specify a null target.
1959 // Get the jsobject associated with this target
1960 // We don't wrap here because we trust the JS engine to wrap the target
1964 rv
= nsContentUtils::WrapNative(mContext
, (JSObject
*)aScope
, aTarget
, &v
);
1965 NS_ENSURE_SUCCESS(rv
, rv
);
1968 nsCOMPtr
<nsISupports
> targetSupp
= do_QueryInterface(aTarget
);
1969 nsCOMPtr
<nsISupports
> native
=
1970 nsContentUtils::XPConnect()->GetNativeOfWrapper(mContext
,
1971 JSVAL_TO_OBJECT(v
));
1972 NS_ASSERTION(native
== targetSupp
, "Native should be the target!");
1975 *aRet
= JSVAL_TO_OBJECT(v
);
1982 nsJSContext::CompileEventHandler(nsIAtom
*aName
,
1984 const char** aArgNames
,
1985 const nsAString
& aBody
,
1986 const char *aURL
, PRUint32 aLineNo
,
1988 nsScriptObjectHolder
&aHandler
)
1990 NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (url: %s, line: %d)", MOZ_FUNCTION_NAME
,
1991 __LINE__
, aURL
, aLineNo
);
1993 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
1995 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
1996 NS_PRECONDITION(!::JS_IsExceptionPending(mContext
),
1997 "Why are we being called with a pending exception?");
1999 if (!sSecurityManager
) {
2000 NS_ERROR("Huh, we need a script security manager to compile "
2001 "an event handler!");
2003 return NS_ERROR_UNEXPECTED
;
2006 // Don't compile if aVersion is unknown. Since the caller is responsible for
2007 // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
2008 if ((JSVersion
)aVersion
== JSVERSION_UNKNOWN
) {
2009 return NS_ERROR_ILLEGAL_VALUE
;
2013 JSContext
* top
= nsContentUtils::GetCurrentJSContext();
2014 NS_ASSERTION(mContext
== top
, "Context not properly pushed!");
2017 // Event handlers are always shared, and must be bound before use.
2018 // Therefore we never bother compiling with principals.
2019 // (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
2020 JSAutoRequest
ar(mContext
);
2023 ::JS_CompileUCFunctionForPrincipalsVersion(mContext
,
2025 nsAtomCString(aName
).get(), aArgCount
, aArgNames
,
2026 (jschar
*)PromiseFlatString(aBody
).get(),
2028 aURL
, aLineNo
, JSVersion(aVersion
));
2031 ReportPendingException();
2032 return NS_ERROR_ILLEGAL_VALUE
;
2035 JSObject
*handler
= ::JS_GetFunctionObject(fun
);
2036 NS_ASSERTION(aHandler
.getScriptTypeID()==JAVASCRIPT
,
2037 "Expecting JS script object holder");
2038 return aHandler
.set((void *)handler
);
2041 // XXX - note that CompileFunction doesn't yet play the nsScriptObjectHolder
2042 // game - caller must still ensure JS GC root.
2044 nsJSContext::CompileFunction(void* aTarget
,
2045 const nsACString
& aName
,
2047 const char** aArgArray
,
2048 const nsAString
& aBody
,
2053 void** aFunctionObject
)
2055 NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s, url: %s, line: %d)", MOZ_FUNCTION_NAME
,
2056 __LINE__
, aName
.BeginReading(), aURL
, aLineNo
);
2058 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
2060 // Don't compile if aVersion is unknown. Since the caller is responsible for
2061 // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
2062 if ((JSVersion
)aVersion
== JSVERSION_UNKNOWN
) {
2063 return NS_ERROR_ILLEGAL_VALUE
;
2066 JSPrincipals
*jsprin
= nsnull
;
2068 nsIScriptGlobalObject
*global
= GetGlobalObject();
2070 // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
2071 nsCOMPtr
<nsIScriptObjectPrincipal
> globalData
= do_QueryInterface(global
);
2073 nsIPrincipal
*prin
= globalData
->GetPrincipal();
2075 return NS_ERROR_FAILURE
;
2076 prin
->GetJSPrincipals(mContext
, &jsprin
);
2080 JSObject
*target
= (JSObject
*)aTarget
;
2082 JSAutoRequest
ar(mContext
);
2085 ::JS_CompileUCFunctionForPrincipalsVersion(mContext
,
2086 aShared
? nsnull
: target
, jsprin
,
2087 PromiseFlatCString(aName
).get(),
2088 aArgCount
, aArgArray
,
2089 (jschar
*)PromiseFlatString(aBody
).get(),
2092 JSVersion(aVersion
));
2095 JSPRINCIPALS_DROP(mContext
, jsprin
);
2097 return NS_ERROR_FAILURE
;
2099 JSObject
*handler
= ::JS_GetFunctionObject(fun
);
2100 if (aFunctionObject
)
2101 *aFunctionObject
= (void*) handler
;
2106 nsJSContext::CallEventHandler(nsISupports
* aTarget
, void *aScope
, void *aHandler
,
2107 nsIArray
*aargv
, nsIVariant
**arv
)
2109 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
2111 if (!mScriptsEnabled
) {
2115 #ifdef NS_FUNCTION_TIMER
2117 JSObject
*obj
= static_cast<JSObject
*>(aHandler
);
2118 JSString
*id
= JS_GetFunctionId(static_cast<JSFunction
*>(JS_GetPrivate(mContext
, obj
)));
2119 JSAutoByteString bytes
;
2120 const char *name
= !id
? "anonymous" : bytes
.encode(mContext
, id
) ? bytes
.ptr() : "<error>";
2121 NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME
, __LINE__
, name
);
2125 JSAutoRequest
ar(mContext
);
2126 JSObject
* target
= nsnull
;
2127 nsresult rv
= JSObjectFromInterface(aTarget
, aScope
, &target
);
2128 NS_ENSURE_SUCCESS(rv
, rv
);
2130 js::AutoObjectRooter
targetVal(mContext
, target
);
2131 jsval rval
= JSVAL_VOID
;
2133 // This one's a lot easier than EvaluateString because we don't have to
2134 // hassle with principals: they're already compiled into the JS function.
2135 // xxxmarkh - this comment is no longer true - principals are not used at
2136 // all now, and never were in some cases.
2138 nsCOMPtr
<nsIJSContextStack
> stack
=
2139 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
2140 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
)))
2141 return NS_ERROR_FAILURE
;
2143 // check if the event handler can be run on the object in question
2144 rv
= sSecurityManager
->CheckFunctionAccess(mContext
, aHandler
, target
);
2146 nsJSContext::TerminationFuncHolder
holder(this);
2148 if (NS_SUCCEEDED(rv
)) {
2149 // Convert args to jsvals.
2151 jsval
*argv
= nsnull
;
2153 js::LazilyConstructed
<nsAutoPoolRelease
> poolRelease
;
2154 js::LazilyConstructed
<js::AutoArrayRooter
> tvr
;
2156 // Use |target| as the scope for wrapping the arguments, since aScope is
2157 // the safe scope in many cases, which isn't very useful. Wrapping aTarget
2158 // was OK because those typically have PreCreate methods that give them the
2159 // right scope anyway, and we want to make sure that the arguments end up
2160 // in the same scope as aTarget.
2161 rv
= ConvertSupportsTojsvals(aargv
, target
, &argc
,
2162 &argv
, poolRelease
, tvr
);
2163 if (NS_FAILED(rv
)) {
2168 jsval funval
= OBJECT_TO_JSVAL(static_cast<JSObject
*>(aHandler
));
2169 JSAutoEnterCompartment ac
;
2170 if (!ac
.enter(mContext
, target
)) {
2172 return NS_ERROR_FAILURE
;
2176 PRBool ok
= ::JS_CallFunctionValue(mContext
, target
,
2177 funval
, argc
, argv
, &rval
);
2181 // Tell XPConnect about any pending exceptions. This is needed
2182 // to avoid dropping JS exceptions in case we got here through
2183 // nested calls through XPConnect.
2185 ReportPendingException();
2187 // Don't pass back results from failed calls.
2190 // Tell the caller that the handler threw an error.
2191 rv
= NS_ERROR_FAILURE
;
2195 if (NS_FAILED(stack
->Pop(nsnull
)))
2196 return NS_ERROR_FAILURE
;
2198 // Convert to variant before calling ScriptEvaluated, as it may GC, meaning
2199 // we would need to root rval.
2200 if (NS_SUCCEEDED(rv
)) {
2201 if (rval
== JSVAL_NULL
)
2204 rv
= nsContentUtils::XPConnect()->JSToVariant(mContext
, rval
, arv
);
2207 // ScriptEvaluated needs to come after we pop the stack
2208 ScriptEvaluated(PR_TRUE
);
2214 nsJSContext::BindCompiledEventHandler(nsISupports
* aTarget
, void *aScope
,
2218 NS_ENSURE_ARG(aHandler
);
2219 NS_ENSURE_TRUE(mIsInitialized
, NS_ERROR_NOT_INITIALIZED
);
2221 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
2224 // Get the jsobject associated with this target
2225 JSObject
*target
= nsnull
;
2226 nsAutoGCRoot
root(&target
, &rv
);
2227 NS_ENSURE_SUCCESS(rv
, rv
);
2228 rv
= JSObjectFromInterface(aTarget
, aScope
, &target
);
2229 NS_ENSURE_SUCCESS(rv
, rv
);
2231 JSObject
*funobj
= (JSObject
*) aHandler
;
2232 JSAutoRequest
ar(mContext
);
2236 JSAutoEnterCompartment ac
;
2237 if (!ac
.enter(mContext
, funobj
)) {
2238 return NS_ERROR_FAILURE
;
2241 NS_ASSERTION(JS_TypeOfValue(mContext
,
2242 OBJECT_TO_JSVAL(funobj
)) == JSTYPE_FUNCTION
,
2243 "Event handler object not a function");
2247 JSAutoEnterCompartment ac
;
2248 if (!ac
.enter(mContext
, target
)) {
2249 return NS_ERROR_FAILURE
;
2252 // Push our JSContext on our thread's context stack, in case native code
2253 // called from JS calls back into JS via XPConnect.
2254 nsCOMPtr
<nsIJSContextStack
> stack
=
2255 do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
2256 if (NS_FAILED(rv
) || NS_FAILED(stack
->Push(mContext
))) {
2257 return NS_ERROR_FAILURE
;
2260 // Make sure the handler function is parented by its event target object
2261 if (funobj
) { // && ::JS_GetParent(mContext, funobj) != target) {
2262 funobj
= ::JS_CloneFunctionObject(mContext
, funobj
, target
);
2264 rv
= NS_ERROR_OUT_OF_MEMORY
;
2267 if (NS_SUCCEEDED(rv
) &&
2268 // Make sure the flags here match those in nsEventReceiverSH::NewResolve
2269 !::JS_DefineProperty(mContext
, target
, nsAtomCString(aName
).get(),
2270 OBJECT_TO_JSVAL(funobj
), nsnull
, nsnull
,
2271 JSPROP_ENUMERATE
| JSPROP_PERMANENT
)) {
2272 ReportPendingException();
2273 rv
= NS_ERROR_FAILURE
;
2276 // XXXmarkh - ideally we should assert that the wrapped native is now
2277 // "long lived" - how to do that?
2279 if (NS_FAILED(stack
->Pop(nsnull
)) && NS_SUCCEEDED(rv
)) {
2280 rv
= NS_ERROR_FAILURE
;
2287 nsJSContext::GetBoundEventHandler(nsISupports
* aTarget
, void *aScope
,
2289 nsScriptObjectHolder
&aHandler
)
2291 NS_PRECONDITION(AtomIsEventHandlerName(aName
), "Bad event name");
2294 JSObject
*obj
= nsnull
;
2295 nsAutoGCRoot
root(&obj
, &rv
);
2296 NS_ENSURE_SUCCESS(rv
, rv
);
2297 JSAutoRequest
ar(mContext
);
2298 rv
= JSObjectFromInterface(aTarget
, aScope
, &obj
);
2299 NS_ENSURE_SUCCESS(rv
, rv
);
2301 JSAutoEnterCompartment ac
;
2302 if (!ac
.enter(mContext
, obj
)) {
2303 return NS_ERROR_FAILURE
;
2307 if (!JS_LookupProperty(mContext
, obj
,
2308 nsAtomCString(aName
).get(), &funval
))
2309 return NS_ERROR_FAILURE
;
2311 if (JS_TypeOfValue(mContext
, funval
) != JSTYPE_FUNCTION
) {
2312 NS_WARNING("Event handler object not a function");
2316 NS_ASSERTION(aHandler
.getScriptTypeID()==JAVASCRIPT
,
2317 "Expecting JS script object holder");
2318 return aHandler
.set(JSVAL_TO_OBJECT(funval
));
2323 nsJSContext::Serialize(nsIObjectOutputStream
* aStream
, void *aScriptObject
)
2325 JSObject
*mJSObject
= (JSObject
*)aScriptObject
;
2327 return NS_ERROR_FAILURE
;
2331 JSContext
* cx
= mContext
;
2332 JSXDRState
*xdr
= ::JS_XDRNewMem(cx
, JSXDR_ENCODE
);
2334 return NS_ERROR_OUT_OF_MEMORY
;
2335 xdr
->userdata
= (void*) aStream
;
2337 JSAutoRequest
ar(cx
);
2338 JSScript
*script
= reinterpret_cast<JSScript
*>
2339 (::JS_GetPrivate(cx
, mJSObject
));
2340 if (! ::JS_XDRScript(xdr
, &script
)) {
2341 rv
= NS_ERROR_FAILURE
; // likely to be a principals serialization error
2343 // Get the encoded JSXDRState data and write it. The JSXDRState owns
2344 // this buffer memory and will free it beneath ::JS_XDRDestroy.
2346 // If an XPCOM object needs to be written in the midst of the JS XDR
2347 // encoding process, the C++ code called back from the JS engine (e.g.,
2348 // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data
2349 // from the JSXDRState to aStream, then write the object, then return
2350 // to JS XDR code with xdr reset so new JS data is encoded at the front
2351 // of the xdr's data buffer.
2353 // However many XPCOM objects are interleaved with JS XDR data in the
2354 // stream, when control returns here from ::JS_XDRScript, we'll have
2355 // one last buffer of data to write to aStream.
2358 const char* data
= reinterpret_cast<const char*>
2359 (::JS_XDRMemGetData(xdr
, &size
));
2360 NS_ASSERTION(data
, "no decoded JSXDRState data!");
2362 rv
= aStream
->Write32(size
);
2363 if (NS_SUCCEEDED(rv
))
2364 rv
= aStream
->WriteBytes(data
, size
);
2367 ::JS_XDRDestroy(xdr
);
2368 if (NS_FAILED(rv
)) return rv
;
2374 nsJSContext::Deserialize(nsIObjectInputStream
* aStream
,
2375 nsScriptObjectHolder
&aResult
)
2377 JSObject
*result
= nsnull
;
2380 NS_TIME_FUNCTION_MIN(1.0);
2382 NS_TIMELINE_MARK_FUNCTION("js script deserialize");
2385 rv
= aStream
->Read32(&size
);
2386 if (NS_FAILED(rv
)) return rv
;
2389 rv
= aStream
->ReadBytes(size
, &data
);
2390 if (NS_FAILED(rv
)) return rv
;
2392 JSContext
* cx
= mContext
;
2394 JSXDRState
*xdr
= ::JS_XDRNewMem(cx
, JSXDR_DECODE
);
2396 rv
= NS_ERROR_OUT_OF_MEMORY
;
2398 xdr
->userdata
= (void*) aStream
;
2399 JSAutoRequest
ar(cx
);
2400 ::JS_XDRMemSetData(xdr
, data
, size
);
2402 JSScript
*script
= nsnull
;
2403 if (! ::JS_XDRScript(xdr
, &script
)) {
2404 rv
= NS_ERROR_FAILURE
; // principals deserialization error?
2406 result
= ::JS_NewScriptObject(cx
, script
);
2408 rv
= NS_ERROR_OUT_OF_MEMORY
; // certain error
2409 ::JS_DestroyScript(cx
, script
);
2413 // Update data in case ::JS_XDRScript called back into C++ code to
2414 // read an XPCOM object.
2416 // In that case, the serialization process must have flushed a run
2417 // of counted bytes containing JS data at the point where the XPCOM
2418 // object starts, after which an encoding C++ callback from the JS
2419 // XDR code must have written the XPCOM object directly into the
2420 // nsIObjectOutputStream.
2422 // The deserialization process will XDR-decode counted bytes up to
2423 // but not including the XPCOM object, then call back into C++ to
2424 // read the object, then read more counted bytes and hand them off
2425 // to the JSXDRState, so more JS data can be decoded.
2427 // This interleaving of JS XDR data and XPCOM object data may occur
2428 // several times beneath the call to ::JS_XDRScript, above. At the
2429 // end of the day, we need to free (via nsMemory) the data owned by
2430 // the JSXDRState. So we steal it back, nulling xdr's buffer so it
2431 // doesn't get passed to ::JS_free by ::JS_XDRDestroy.
2434 data
= (char*) ::JS_XDRMemGetData(xdr
, &junk
);
2436 ::JS_XDRMemSetData(xdr
, NULL
, 0);
2437 ::JS_XDRDestroy(xdr
);
2440 // If data is null now, it must have been freed while deserializing an
2441 // XPCOM object (e.g., a principal) beneath ::JS_XDRScript.
2443 nsMemory::Free(data
);
2444 NS_ASSERTION(aResult
.getScriptTypeID()==JAVASCRIPT
,
2445 "Expecting JS script object holder");
2447 // Now that we've cleaned up, handle the case when rv is a failure
2448 // code, which could happen for all sorts of reasons above.
2449 NS_ENSURE_SUCCESS(rv
, rv
);
2451 return aResult
.set(result
);
2455 nsJSContext::SetDefaultLanguageVersion(PRUint32 aVersion
)
2457 ::JS_SetVersion(mContext
, (JSVersion
)aVersion
);
2460 nsIScriptGlobalObject
*
2461 nsJSContext::GetGlobalObject()
2463 JSObject
*global
= ::JS_GetGlobalObject(mContext
);
2469 OBJ_TO_INNER_OBJECT(mContext
, global
);
2474 JSClass
*c
= JS_GET_CLASS(mContext
, global
);
2476 if (!c
|| ((~c
->flags
) & (JSCLASS_HAS_PRIVATE
|
2477 JSCLASS_PRIVATE_IS_NSISUPPORTS
))) {
2481 JSAutoEnterCompartment ac
;
2483 // NB: This AutoCrossCompartmentCall is only here to silence a warning. If
2484 // it fails, nothing bad will happen.
2485 ac
.enterAndIgnoreErrors(mContext
, global
);
2487 nsCOMPtr
<nsIScriptGlobalObject
> sgo
;
2489 (nsISupports
*)::JS_GetPrivate(mContext
, global
);
2491 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapped_native
=
2492 do_QueryInterface(priv
);
2494 if (wrapped_native
) {
2495 // The global object is a XPConnect wrapped native, the native in
2496 // the wrapper might be the nsIScriptGlobalObject
2498 sgo
= do_QueryWrappedNative(wrapped_native
);
2500 sgo
= do_QueryInterface(priv
);
2503 // This'll return a pointer to something we're about to release, but
2504 // that's ok, the JS object will hold it alive long enough.
2505 nsCOMPtr
<nsPIDOMWindow
> pwin(do_QueryInterface(sgo
));
2509 return static_cast<nsGlobalWindow
*>(pwin
->GetOuterWindow());
2513 nsJSContext::GetNativeGlobal()
2515 return ::JS_GetGlobalObject(mContext
);
2519 nsJSContext::CreateNativeGlobalForInner(
2520 nsIScriptGlobalObject
*aNewInner
,
2522 nsIPrincipal
*aPrincipal
,
2523 void **aNativeGlobal
, nsISupports
**aHolder
)
2525 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2526 PRUint32 flags
= aIsChrome
? nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT
: 0;
2527 nsCOMPtr
<nsIXPConnectJSObjectHolder
> jsholder
;
2529 nsCOMPtr
<nsIPrincipal
> systemPrincipal
;
2531 nsIScriptSecurityManager
*ssm
= nsContentUtils::GetSecurityManager();
2532 ssm
->GetSystemPrincipal(getter_AddRefs(systemPrincipal
));
2536 InitClassesWithNewWrappedGlobal(mContext
,
2537 aNewInner
, NS_GET_IID(nsISupports
),
2538 aIsChrome
? systemPrincipal
.get() : aPrincipal
,
2540 getter_AddRefs(jsholder
));
2543 jsholder
->GetJSObject(reinterpret_cast<JSObject
**>(aNativeGlobal
));
2544 *aHolder
= jsholder
.get();
2545 NS_ADDREF(*aHolder
);
2550 nsJSContext::ConnectToInner(nsIScriptGlobalObject
*aNewInner
, void *aOuterGlobal
)
2552 NS_ENSURE_ARG(aNewInner
);
2553 JSObject
*newInnerJSObject
= (JSObject
*)aNewInner
->GetScriptGlobal(JAVASCRIPT
);
2554 JSObject
*outerGlobal
= (JSObject
*)aOuterGlobal
;
2556 // Make the inner and outer window both share the same
2557 // prototype. The prototype we share is the outer window's
2558 // prototype, this way XPConnect can still find the wrapper to
2559 // use when making a call like alert() (w/o qualifying it with
2560 // "window."). XPConnect looks up the wrapper based on the
2561 // function object's parent, which is the object the function
2562 // was called on, and when calling alert() we'll be calling the
2563 // alert() function from the outer window's prototype off of the
2564 // inner window. In this case XPConnect is able to find the
2565 // outer (through the JSExtendedClass hook outerObject), so this
2566 // prototype sharing works.
2568 // Now that we're connecting the outer global to the inner one,
2569 // we must have transplanted it. The JS engine tries to maintain
2570 // the global object's compartment as its default compartment,
2571 // so update that now since it might have changed.
2572 JS_SetGlobalObject(mContext
, outerGlobal
);
2574 // We do *not* want to use anything else out of the outer
2575 // object's prototype chain than the first prototype, which is
2576 // the XPConnect prototype. The rest we want from the inner
2577 // window's prototype, i.e. the global scope polluter and
2578 // Object.prototype. This way the outer also gets the benefits
2579 // of the global scope polluter, and the inner window's
2580 // Object.prototype.
2581 JSObject
*proto
= JS_GetPrototype(mContext
, outerGlobal
);
2582 JSObject
*innerProto
= JS_GetPrototype(mContext
, newInnerJSObject
);
2583 JSObject
*innerProtoProto
= JS_GetPrototype(mContext
, innerProto
);
2585 JS_SetPrototype(mContext
, newInnerJSObject
, proto
);
2586 JS_SetPrototype(mContext
, proto
, innerProtoProto
);
2592 nsJSContext::GetNativeContext()
2598 nsJSContext::InitContext()
2600 // Make sure callers of this use
2601 // WillInitializeContext/DidInitializeContext around this call.
2602 NS_ENSURE_TRUE(!mIsInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
2605 return NS_ERROR_OUT_OF_MEMORY
;
2607 ::JS_SetErrorReporter(mContext
, NS_ScriptErrorReporter
);
2613 nsJSContext::CreateOuterObject(nsIScriptGlobalObject
*aGlobalObject
,
2614 nsIScriptGlobalObject
*aCurrentInner
)
2616 mGlobalObjectRef
= aGlobalObject
;
2618 nsCOMPtr
<nsIDOMChromeWindow
> chromeWindow(do_QueryInterface(aGlobalObject
));
2622 // Flag this window's global object and objects under it as "system",
2623 // for optional automated XPCNativeWrapper construction when chrome JS
2624 // views a content DOM.
2625 flags
= nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT
;
2627 // Always enable E4X for XUL and other chrome content -- there is no
2628 // need to preserve the <!-- script hiding hack from JS-in-HTML daze
2629 // (introduced in 1995 for graceful script degradation in Netscape 1,
2630 // Mosaic, and other pre-JS browsers).
2631 JS_SetOptions(mContext
, JS_GetOptions(mContext
) | JSOPTION_XML
);
2634 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2635 nsCOMPtr
<nsIXPConnectJSObjectHolder
> holder
;
2637 nsresult rv
= xpc
->WrapNative(mContext
, aCurrentInner
->GetGlobalJSObject(),
2638 aCurrentInner
, NS_GET_IID(nsISupports
),
2639 getter_AddRefs(holder
));
2640 NS_ENSURE_SUCCESS(rv
, rv
);
2642 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper(do_QueryInterface(holder
));
2643 NS_ABORT_IF_FALSE(wrapper
, "bad wrapper");
2645 wrapper
->RefreshPrototype();
2648 NS_NewOuterWindowProxy(mContext
, aCurrentInner
->GetGlobalJSObject());
2650 return NS_ERROR_FAILURE
;
2653 return SetOuterObject(outer
);
2657 nsJSContext::SetOuterObject(void *aOuterObject
)
2659 JSObject
*outer
= static_cast<JSObject
*>(aOuterObject
);
2661 // Force our context's global object to be the outer.
2662 JS_SetGlobalObject(mContext
, outer
);
2667 nsJSContext::InitOuterWindow()
2669 JSObject
*global
= JS_GetGlobalObject(mContext
);
2670 OBJ_TO_INNER_OBJECT(mContext
, global
);
2672 nsresult rv
= InitClasses(global
); // this will complete global object initialization
2673 NS_ENSURE_SUCCESS(rv
, rv
);
2679 nsJSContext::InitializeExternalClasses()
2681 nsScriptNameSpaceManager
*nameSpaceManager
= nsJSRuntime::GetNameSpaceManager();
2682 NS_ENSURE_TRUE(nameSpaceManager
, NS_ERROR_NOT_INITIALIZED
);
2684 return nameSpaceManager
->InitForContext(this);
2688 nsJSContext::SetProperty(void *aTarget
, const char *aPropName
, nsISupports
*aArgs
)
2691 jsval
*argv
= nsnull
;
2693 JSAutoRequest
ar(mContext
);
2695 js::LazilyConstructed
<nsAutoPoolRelease
> poolRelease
;
2696 js::LazilyConstructed
<js::AutoArrayRooter
> tvr
;
2699 rv
= ConvertSupportsTojsvals(aArgs
, GetNativeGlobal(), &argc
,
2700 &argv
, poolRelease
, tvr
);
2701 NS_ENSURE_SUCCESS(rv
, rv
);
2705 // got the arguments, now attach them.
2707 // window.dialogArguments is supposed to be an array if a JS array
2708 // was passed to showModalDialog(), deal with that here.
2709 if (strcmp(aPropName
, "dialogArguments") == 0 && argc
<= 1) {
2710 vargs
= argc
? argv
[0] : JSVAL_VOID
;
2712 for (PRUint32 i
= 0; i
< argc
; ++i
) {
2713 if (!JS_WrapValue(mContext
, &argv
[i
])) {
2714 return NS_ERROR_FAILURE
;
2718 JSObject
*args
= ::JS_NewArrayObject(mContext
, argc
, argv
);
2719 vargs
= OBJECT_TO_JSVAL(args
);
2722 // Make sure to use JS_DefineProperty here so that we can override
2723 // readonly XPConnect properties here as well (read dialogArguments).
2724 rv
= ::JS_DefineProperty(mContext
, reinterpret_cast<JSObject
*>(aTarget
),
2725 aPropName
, vargs
, nsnull
, nsnull
, 0) ?
2726 NS_OK
: NS_ERROR_FAILURE
;
2732 nsJSContext::ConvertSupportsTojsvals(nsISupports
*aArgs
,
2736 js::LazilyConstructed
<nsAutoPoolRelease
> &aPoolRelease
,
2737 js::LazilyConstructed
<js::AutoArrayRooter
> &aRooter
)
2739 nsresult rv
= NS_OK
;
2741 // If the array implements nsIJSArgArray, just grab the values directly.
2742 nsCOMPtr
<nsIJSArgArray
> fastArray
= do_QueryInterface(aArgs
);
2743 if (fastArray
!= nsnull
)
2744 return fastArray
->GetArgs(aArgc
, reinterpret_cast<void **>(aArgv
));
2746 // Take the slower path converting each item.
2747 // Handle only nsIArray and nsIVariant. nsIArray is only needed for
2748 // SetProperty('arguments', ...);
2753 nsIXPConnect
*xpc
= nsContentUtils::XPConnect();
2754 NS_ENSURE_TRUE(xpc
, NS_ERROR_UNEXPECTED
);
2758 PRUint32 argCtr
, argCount
;
2759 // This general purpose function may need to convert an arg array
2760 // (window.arguments, event-handler args) and a generic property.
2761 nsCOMPtr
<nsIArray
> argsArray(do_QueryInterface(aArgs
));
2764 rv
= argsArray
->GetLength(&argCount
);
2765 NS_ENSURE_SUCCESS(rv
, rv
);
2769 argCount
= 1; // the nsISupports which is not an array
2772 void *mark
= JS_ARENA_MARK(&mContext
->tempPool
);
2774 size_t nbytes
= argCount
* sizeof(jsval
);
2775 JS_ARENA_ALLOCATE_CAST(argv
, jsval
*, &mContext
->tempPool
, nbytes
);
2776 NS_ENSURE_TRUE(argv
, NS_ERROR_OUT_OF_MEMORY
);
2777 memset(argv
, 0, nbytes
); /* initialize so GC-able */
2779 // Use the caller's auto guards to release and unroot.
2780 aPoolRelease
.construct(&mContext
->tempPool
, mark
);
2781 aRooter
.construct(mContext
, argCount
, argv
);
2784 for (argCtr
= 0; argCtr
< argCount
&& NS_SUCCEEDED(rv
); argCtr
++) {
2785 nsCOMPtr
<nsISupports
> arg
;
2786 jsval
*thisval
= argv
+ argCtr
;
2787 argsArray
->QueryElementAt(argCtr
, NS_GET_IID(nsISupports
),
2788 getter_AddRefs(arg
));
2790 *thisval
= JSVAL_NULL
;
2793 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(arg
));
2794 if (variant
!= nsnull
) {
2795 rv
= xpc
->VariantToJS(mContext
, (JSObject
*)aScope
, variant
,
2798 // And finally, support the nsISupportsPrimitives supplied
2799 // by the AppShell. It generally will pass only strings, but
2800 // as we have code for handling all, we may as well use it.
2801 rv
= AddSupportsPrimitiveTojsvals(arg
, thisval
);
2802 if (rv
== NS_ERROR_NO_INTERFACE
) {
2803 // something else - probably an event object or similar -
2806 // but first, check its not another nsISupportsPrimitive, as
2807 // these are now deprecated for use with script contexts.
2808 nsCOMPtr
<nsISupportsPrimitive
> prim(do_QueryInterface(arg
));
2809 NS_ASSERTION(prim
== nsnull
,
2810 "Don't pass nsISupportsPrimitives - use nsIVariant!");
2812 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
2814 rv
= nsContentUtils::WrapNative(mContext
, (JSObject
*)aScope
, arg
,
2815 &v
, getter_AddRefs(wrapper
));
2816 if (NS_SUCCEEDED(rv
)) {
2823 nsCOMPtr
<nsIVariant
> variant(do_QueryInterface(aArgs
));
2825 rv
= xpc
->VariantToJS(mContext
, (JSObject
*)aScope
, variant
, argv
);
2827 NS_ERROR("Not an array, not an interface?");
2828 rv
= NS_ERROR_UNEXPECTED
;
2838 // This really should go into xpconnect somewhere...
2840 nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports
*aArg
, jsval
*aArgv
)
2842 NS_PRECONDITION(aArg
, "Empty arg");
2844 nsCOMPtr
<nsISupportsPrimitive
> argPrimitive(do_QueryInterface(aArg
));
2846 return NS_ERROR_NO_INTERFACE
;
2848 JSContext
*cx
= mContext
;
2850 argPrimitive
->GetType(&type
);
2853 case nsISupportsPrimitive::TYPE_CSTRING
: {
2854 nsCOMPtr
<nsISupportsCString
> p(do_QueryInterface(argPrimitive
));
2855 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2862 JSString
*str
= ::JS_NewStringCopyN(cx
, data
.get(), data
.Length());
2863 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2865 *aArgv
= STRING_TO_JSVAL(str
);
2869 case nsISupportsPrimitive::TYPE_STRING
: {
2870 nsCOMPtr
<nsISupportsString
> p(do_QueryInterface(argPrimitive
));
2871 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2877 // cast is probably safe since wchar_t and jschar are expected
2878 // to be equivalent; both unsigned 16-bit entities
2880 ::JS_NewUCStringCopyN(cx
,
2881 reinterpret_cast<const jschar
*>(data
.get()),
2883 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2885 *aArgv
= STRING_TO_JSVAL(str
);
2888 case nsISupportsPrimitive::TYPE_PRBOOL
: {
2889 nsCOMPtr
<nsISupportsPRBool
> p(do_QueryInterface(argPrimitive
));
2890 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2896 *aArgv
= BOOLEAN_TO_JSVAL(data
);
2900 case nsISupportsPrimitive::TYPE_PRUINT8
: {
2901 nsCOMPtr
<nsISupportsPRUint8
> p(do_QueryInterface(argPrimitive
));
2902 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2908 *aArgv
= INT_TO_JSVAL(data
);
2912 case nsISupportsPrimitive::TYPE_PRUINT16
: {
2913 nsCOMPtr
<nsISupportsPRUint16
> p(do_QueryInterface(argPrimitive
));
2914 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2920 *aArgv
= INT_TO_JSVAL(data
);
2924 case nsISupportsPrimitive::TYPE_PRUINT32
: {
2925 nsCOMPtr
<nsISupportsPRUint32
> p(do_QueryInterface(argPrimitive
));
2926 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2932 *aArgv
= INT_TO_JSVAL(data
);
2936 case nsISupportsPrimitive::TYPE_CHAR
: {
2937 nsCOMPtr
<nsISupportsChar
> p(do_QueryInterface(argPrimitive
));
2938 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2944 JSString
*str
= ::JS_NewStringCopyN(cx
, &data
, 1);
2945 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2947 *aArgv
= STRING_TO_JSVAL(str
);
2951 case nsISupportsPrimitive::TYPE_PRINT16
: {
2952 nsCOMPtr
<nsISupportsPRInt16
> p(do_QueryInterface(argPrimitive
));
2953 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2959 *aArgv
= INT_TO_JSVAL(data
);
2963 case nsISupportsPrimitive::TYPE_PRINT32
: {
2964 nsCOMPtr
<nsISupportsPRInt32
> p(do_QueryInterface(argPrimitive
));
2965 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2971 *aArgv
= INT_TO_JSVAL(data
);
2975 case nsISupportsPrimitive::TYPE_FLOAT
: {
2976 nsCOMPtr
<nsISupportsFloat
> p(do_QueryInterface(argPrimitive
));
2977 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2983 JSBool ok
= ::JS_NewNumberValue(cx
, data
, aArgv
);
2984 NS_ENSURE_TRUE(ok
, NS_ERROR_OUT_OF_MEMORY
);
2988 case nsISupportsPrimitive::TYPE_DOUBLE
: {
2989 nsCOMPtr
<nsISupportsDouble
> p(do_QueryInterface(argPrimitive
));
2990 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
2996 JSBool ok
= ::JS_NewNumberValue(cx
, data
, aArgv
);
2997 NS_ENSURE_TRUE(ok
, NS_ERROR_OUT_OF_MEMORY
);
3001 case nsISupportsPrimitive::TYPE_INTERFACE_POINTER
: {
3002 nsCOMPtr
<nsISupportsInterfacePointer
> p(do_QueryInterface(argPrimitive
));
3003 NS_ENSURE_TRUE(p
, NS_ERROR_UNEXPECTED
);
3005 nsCOMPtr
<nsISupports
> data
;
3006 nsIID
*iid
= nsnull
;
3008 p
->GetData(getter_AddRefs(data
));
3009 p
->GetDataIID(&iid
);
3010 NS_ENSURE_TRUE(iid
, NS_ERROR_UNEXPECTED
);
3012 AutoFree
iidGuard(iid
); // Free iid upon destruction.
3014 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
3016 nsresult rv
= nsContentUtils::WrapNative(cx
, ::JS_GetGlobalObject(cx
),
3018 getter_AddRefs(wrapper
));
3019 NS_ENSURE_SUCCESS(rv
, rv
);
3025 case nsISupportsPrimitive::TYPE_ID
:
3026 case nsISupportsPrimitive::TYPE_PRUINT64
:
3027 case nsISupportsPrimitive::TYPE_PRINT64
:
3028 case nsISupportsPrimitive::TYPE_PRTIME
:
3029 case nsISupportsPrimitive::TYPE_VOID
: {
3030 NS_WARNING("Unsupported primitive type used");
3031 *aArgv
= JSVAL_NULL
;
3035 NS_WARNING("Unknown primitive type used");
3036 *aArgv
= JSVAL_NULL
;
3043 static JSPropertySpec OptionsProperties
[] = {
3044 {"strict", (int8
)JSOPTION_STRICT
, JSPROP_ENUMERATE
| JSPROP_PERMANENT
},
3045 {"werror", (int8
)JSOPTION_WERROR
, JSPROP_ENUMERATE
| JSPROP_PERMANENT
},
3046 {"relimit", (int8
)JSOPTION_RELIMIT
, JSPROP_ENUMERATE
| JSPROP_PERMANENT
},
3051 GetOptionsProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
3053 if (JSID_IS_INT(id
)) {
3054 uint32 optbit
= (uint32
) JSID_TO_INT(id
);
3055 if (((optbit
& (optbit
- 1)) == 0 && optbit
<= JSOPTION_WERROR
) ||
3056 optbit
== JSOPTION_RELIMIT
)
3057 *vp
= (JS_GetOptions(cx
) & optbit
) ? JSVAL_TRUE
: JSVAL_FALSE
;
3063 SetOptionsProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
3065 if (JSID_IS_INT(id
)) {
3066 uint32 optbit
= (uint32
) JSID_TO_INT(id
);
3068 // Don't let options other than strict, werror, or relimit be set -- it
3069 // would be bad if web page script could clear
3070 // JSOPTION_PRIVATE_IS_NSISUPPORTS!
3071 if (((optbit
& (optbit
- 1)) == 0 && optbit
<= JSOPTION_WERROR
) ||
3072 optbit
== JSOPTION_RELIMIT
) {
3074 JS_ValueToBoolean(cx
, *vp
, &optval
);
3076 uint32 optset
= ::JS_GetOptions(cx
);
3081 ::JS_SetOptions(cx
, optset
);
3087 static JSClass OptionsClass
= {
3090 JS_PropertyStub
, JS_PropertyStub
, GetOptionsProperty
, SetOptionsProperty
,
3091 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, nsnull
3094 #ifdef NS_TRACE_MALLOC
3096 #include <errno.h> // XXX assume Linux if NS_TRACE_MALLOC
3104 #include "nsTraceMalloc.h"
3107 CheckUniversalXPConnectForTraceMalloc(JSContext
*cx
)
3109 PRBool hasCap
= PR_FALSE
;
3110 nsresult rv
= nsContentUtils::GetSecurityManager()->
3111 IsCapabilityEnabled("UniversalXPConnect", &hasCap
);
3112 if (NS_SUCCEEDED(rv
) && hasCap
)
3114 JS_ReportError(cx
, "trace-malloc functions require UniversalXPConnect");
3119 TraceMallocDisable(JSContext
*cx
, uintN argc
, jsval
*vp
)
3121 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3124 NS_TraceMallocDisable();
3125 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3130 TraceMallocEnable(JSContext
*cx
, uintN argc
, jsval
*vp
)
3132 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3135 NS_TraceMallocEnable();
3136 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3141 TraceMallocOpenLogFile(JSContext
*cx
, uintN argc
, jsval
*vp
)
3146 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3152 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
3155 JSAutoByteString
filename(cx
, str
);
3158 fd
= open(filename
.ptr(), O_CREAT
| O_WRONLY
| O_TRUNC
, 0644);
3160 JS_ReportError(cx
, "can't open %s: %s", filename
.ptr(), strerror(errno
));
3164 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(fd
));
3169 TraceMallocChangeLogFD(JSContext
*cx
, uintN argc
, jsval
*vp
)
3173 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3179 if (!JS_ValueToECMAInt32(cx
, JS_ARGV(cx
, vp
)[0], &fd
))
3181 oldfd
= NS_TraceMallocChangeLogFD(fd
);
3183 JS_ReportOutOfMemory(cx
);
3187 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(oldfd
));
3192 TraceMallocCloseLogFD(JSContext
*cx
, uintN argc
, jsval
*vp
)
3196 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3199 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3202 if (!JS_ValueToECMAInt32(cx
, JS_ARGV(cx
, vp
)[0], &fd
))
3204 NS_TraceMallocCloseLogFD((int) fd
);
3209 TraceMallocLogTimestamp(JSContext
*cx
, uintN argc
, jsval
*vp
)
3211 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3214 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
3217 JSAutoByteString
caption(cx
, str
);
3220 NS_TraceMallocLogTimestamp(caption
.ptr());
3221 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3226 TraceMallocDumpAllocations(JSContext
*cx
, uintN argc
, jsval
*vp
)
3228 if (!CheckUniversalXPConnectForTraceMalloc(cx
))
3231 JSString
*str
= JS_ValueToString(cx
, argc
? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
);
3234 JSAutoByteString
pathname(cx
, str
);
3237 if (NS_TraceMallocDumpAllocations(pathname
.ptr()) < 0) {
3238 JS_ReportError(cx
, "can't dump to %s: %s", pathname
.ptr(), strerror(errno
));
3241 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
3245 static JSFunctionSpec TraceMallocFunctions
[] = {
3246 {"TraceMallocDisable", TraceMallocDisable
, 0, 0},
3247 {"TraceMallocEnable", TraceMallocEnable
, 0, 0},
3248 {"TraceMallocOpenLogFile", TraceMallocOpenLogFile
, 1, 0},
3249 {"TraceMallocChangeLogFD", TraceMallocChangeLogFD
, 1, 0},
3250 {"TraceMallocCloseLogFD", TraceMallocCloseLogFD
, 1, 0},
3251 {"TraceMallocLogTimestamp", TraceMallocLogTimestamp
, 1, 0},
3252 {"TraceMallocDumpAllocations", TraceMallocDumpAllocations
, 1, 0},
3253 {nsnull
, nsnull
, 0, 0}
3256 #endif /* NS_TRACE_MALLOC */
3263 IsJProfAction(struct sigaction
*action
)
3265 return (action
->sa_sigaction
&&
3266 action
->sa_flags
== (SA_RESTART
| SA_SIGINFO
));
3269 void NS_JProfStartProfiling();
3270 void NS_JProfStopProfiling();
3273 JProfStartProfilingJS(JSContext
*cx
, uintN argc
, jsval
*vp
)
3275 NS_JProfStartProfiling();
3279 void NS_JProfStartProfiling()
3281 // Figure out whether we're dealing with SIGPROF, SIGALRM, or
3282 // SIGPOLL profiling (SIGALRM for JP_REALTIME, SIGPOLL for
3284 struct sigaction action
;
3286 sigaction(SIGALRM
, nsnull
, &action
);
3287 if (IsJProfAction(&action
)) {
3288 printf("Beginning real-time jprof profiling.\n");
3293 sigaction(SIGPROF
, nsnull
, &action
);
3294 if (IsJProfAction(&action
)) {
3295 printf("Beginning process-time jprof profiling.\n");
3300 sigaction(SIGPOLL
, nsnull
, &action
);
3301 if (IsJProfAction(&action
)) {
3302 printf("Beginning rtc-based jprof profiling.\n");
3307 printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
3311 JProfStopProfilingJS(JSContext
*cx
, uintN argc
, jsval
*vp
)
3313 NS_JProfStopProfiling();
3318 NS_JProfStopProfiling()
3321 printf("Stopped jprof profiling.\n");
3324 static JSFunctionSpec JProfFunctions
[] = {
3325 {"JProfStartProfiling", JProfStartProfilingJS
, 0, 0},
3326 {"JProfStopProfiling", JProfStopProfilingJS
, 0, 0},
3327 {nsnull
, nsnull
, 0, 0}
3330 #endif /* defined(MOZ_JPROF) */
3333 static JSFunctionSpec SharkFunctions
[] = {
3334 {"startShark", js_StartShark
, 0, 0},
3335 {"stopShark", js_StopShark
, 0, 0},
3336 {"connectShark", js_ConnectShark
, 0, 0},
3337 {"disconnectShark", js_DisconnectShark
, 0, 0},
3338 {nsnull
, nsnull
, 0, 0}
3342 #ifdef MOZ_CALLGRIND
3343 static JSFunctionSpec CallgrindFunctions
[] = {
3344 {"startCallgrind", js_StartCallgrind
, 0, 0},
3345 {"stopCallgrind", js_StopCallgrind
, 0, 0},
3346 {"dumpCallgrind", js_DumpCallgrind
, 1, 0},
3347 {nsnull
, nsnull
, 0, 0}
3352 static JSFunctionSpec VtuneFunctions
[] = {
3353 {"startVtune", js_StartVtune
, 1, 0},
3354 {"stopVtune", js_StopVtune
, 0, 0},
3355 {"pauseVtune", js_PauseVtune
, 0, 0},
3356 {"resumeVtune", js_ResumeVtune
, 0, 0},
3357 {nsnull
, nsnull
, 0, 0}
3362 static JSFunctionSpec EthogramFunctions
[] = {
3363 {"initEthogram", js_InitEthogram
, 0, 0},
3364 {"shutdownEthogram", js_ShutdownEthogram
, 0, 0},
3365 {nsnull
, nsnull
, 0, 0}
3370 nsJSContext::InitClasses(void *aGlobalObj
)
3372 nsresult rv
= NS_OK
;
3374 JSObject
*globalObj
= static_cast<JSObject
*>(aGlobalObj
);
3376 rv
= InitializeExternalClasses();
3377 NS_ENSURE_SUCCESS(rv
, rv
);
3379 JSAutoRequest
ar(mContext
);
3381 // Initialize the options object and set default options in mContext
3382 JSObject
*optionsObj
= ::JS_DefineObject(mContext
, globalObj
, "_options",
3383 &OptionsClass
, nsnull
, 0);
3385 ::JS_DefineProperties(mContext
, optionsObj
, OptionsProperties
)) {
3386 ::JS_SetOptions(mContext
, mDefaultJSOptions
);
3388 rv
= NS_ERROR_FAILURE
;
3391 #ifdef NS_TRACE_MALLOC
3392 // Attempt to initialize TraceMalloc functions
3393 ::JS_DefineFunctions(mContext
, globalObj
, TraceMallocFunctions
);
3397 // Attempt to initialize JProf functions
3398 ::JS_DefineFunctions(mContext
, globalObj
, JProfFunctions
);
3402 // Attempt to initialize Shark functions
3403 ::JS_DefineFunctions(mContext
, globalObj
, SharkFunctions
);
3406 #ifdef MOZ_CALLGRIND
3407 // Attempt to initialize Callgrind functions
3408 ::JS_DefineFunctions(mContext
, globalObj
, CallgrindFunctions
);
3412 // Attempt to initialize Vtune functions
3413 ::JS_DefineFunctions(mContext
, globalObj
, VtuneFunctions
);
3417 // Attempt to initialize Ethogram functions
3418 ::JS_DefineFunctions(mContext
, globalObj
, EthogramFunctions
);
3421 JSOptionChangedCallback(js_options_dot_str
, this);
3427 nsJSContext::ClearScope(void *aGlobalObj
, PRBool aClearFromProtoChain
)
3429 // Push our JSContext on our thread's context stack.
3430 nsCOMPtr
<nsIJSContextStack
> stack
=
3431 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
3432 if (stack
&& NS_FAILED(stack
->Push(mContext
))) {
3437 JSObject
*obj
= (JSObject
*)aGlobalObj
;
3438 JSAutoRequest
ar(mContext
);
3440 JSAutoEnterCompartment ac
;
3441 ac
.enterAndIgnoreErrors(mContext
, obj
);
3443 JS_ClearScope(mContext
, obj
);
3444 if (xpc::WrapperFactory::IsXrayWrapper(obj
)) {
3445 JS_ClearScope(mContext
, &obj
->getProxyExtra().toObject());
3447 if (!obj
->getParent()) {
3448 JS_ClearRegExpStatics(mContext
, obj
);
3451 // Always clear watchpoints, to deal with two cases:
3452 // 1. The first document for this window is loading, and a miscreant has
3453 // preset watchpoints on the window object in order to attack the new
3454 // document's privileged information.
3455 // 2. A document loaded and used watchpoints on its own window, leaving
3456 // them set until the next document loads. We must clean up window
3457 // watchpoints here.
3458 // Watchpoints set on document and subordinate objects are all cleared
3459 // when those sub-window objects are finalized, after JS_ClearScope and
3460 // a GC run that finds them to be garbage.
3461 ::JS_ClearWatchPointsForObject(mContext
, obj
);
3463 // Since the prototype chain is shared between inner and outer (and
3464 // stays with the inner), we don't clear things from the prototype
3465 // chain when we're clearing an outer window whose current inner we
3467 if (aClearFromProtoChain
) {
3468 nsWindowSH::InvalidateGlobalScopePolluter(mContext
, obj
);
3470 // Clear up obj's prototype chain, but not Object.prototype.
3471 for (JSObject
*o
= ::JS_GetPrototype(mContext
, obj
), *next
;
3472 o
&& (next
= ::JS_GetPrototype(mContext
, o
)); o
= next
)
3473 ::JS_ClearScope(mContext
, o
);
3483 nsJSContext::WillInitializeContext()
3485 mIsInitialized
= PR_FALSE
;
3489 nsJSContext::DidInitializeContext()
3491 mIsInitialized
= PR_TRUE
;
3495 nsJSContext::IsContextInitialized()
3497 return mIsInitialized
;
3501 nsJSContext::FinalizeContext()
3509 FireGCTimer(PR_FALSE
);
3513 nsJSContext::ScriptEvaluated(PRBool aTerminated
)
3515 if (aTerminated
&& mTerminations
) {
3516 // Make sure to null out mTerminations before doing anything that
3517 // might cause new termination funcs to be added!
3518 nsJSContext::TerminationFuncClosure
* start
= mTerminations
;
3519 mTerminations
= nsnull
;
3521 for (nsJSContext::TerminationFuncClosure
* cur
= start
;
3524 (*(cur
->mTerminationFunc
))(cur
->mTerminationFuncArg
);
3532 if (mContext
->runtime
->gcZeal
>= 2) {
3536 if (mNumEvaluations
> 20) {
3537 mNumEvaluations
= 0;
3542 mOperationCallbackTime
= 0;
3543 mModalStateTime
= 0;
3548 nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc
,
3551 NS_PRECONDITION(JS_IsRunning(mContext
), "should be executing script");
3553 nsJSContext::TerminationFuncClosure
* newClosure
=
3554 new nsJSContext::TerminationFuncClosure(aFunc
, aRef
, mTerminations
);
3556 return NS_ERROR_OUT_OF_MEMORY
;
3559 mTerminations
= newClosure
;
3564 nsJSContext::GetScriptsEnabled()
3566 return mScriptsEnabled
;
3570 nsJSContext::SetScriptsEnabled(PRBool aEnabled
, PRBool aFireTimeouts
)
3572 // eeek - this seems the wrong way around - the global should callback
3573 // into each context, so every language is disabled.
3574 mScriptsEnabled
= aEnabled
;
3576 nsIScriptGlobalObject
*global
= GetGlobalObject();
3579 global
->SetScriptsEnabled(aEnabled
, aFireTimeouts
);
3585 nsJSContext::GetProcessingScriptTag()
3587 return mProcessingScriptTag
;
3591 nsJSContext::SetProcessingScriptTag(PRBool aFlag
)
3593 mProcessingScriptTag
= aFlag
;
3597 nsJSContext::GetExecutingScript()
3599 return JS_IsRunning(mContext
) || mExecuteDepth
> 0;
3603 nsJSContext::SetGCOnDestruction(PRBool aGCOnDestruction
)
3605 mGCOnDestruction
= aGCOnDestruction
;
3609 nsJSContext::ScriptExecuted()
3611 ScriptEvaluated(!::JS_IsRunning(mContext
));
3618 nsJSContext::CC(nsICycleCollectorListener
*aListener
)
3620 NS_TIME_FUNCTION_MIN(1.0);
3624 printf("Will run cycle collector (%i), %lldms since previous.\n",
3625 sCCollectCount
, (PR_Now() - sPreviousCCTime
) / PR_USEC_PER_MSEC
);
3627 sPreviousCCTime
= PR_Now();
3628 sDelayedCCollectCount
= 0;
3629 sCCSuspectChanges
= 0;
3630 // nsCycleCollector_collect() no longer forces a JS garbage collection,
3631 // so we have to do it ourselves here.
3632 if (nsContentUtils::XPConnect()) {
3633 nsContentUtils::XPConnect()->GarbageCollect();
3635 sCollectedObjectsCounts
= nsCycleCollector_collect(aListener
);
3636 sCCSuspectedCount
= nsCycleCollector_suspectedCount();
3637 if (nsJSRuntime::sRuntime
) {
3638 sSavedGCCount
= JS_GetGCParameter(nsJSRuntime::sRuntime
, JSGC_NUMBER
);
3641 printf("Collected %u objects, %u suspected objects, took %lldms\n",
3642 sCollectedObjectsCounts
, sCCSuspectedCount
,
3643 (PR_Now() - sPreviousCCTime
) / PR_USEC_PER_MSEC
);
3647 static inline uint32
3648 GetGCRunsSinceLastCC()
3650 // To avoid crash if nsJSRuntime is not properly initialized.
3651 // See the bug 474586
3652 if (!nsJSRuntime::sRuntime
)
3655 // Since JS_GetGCParameter() and sSavedGCCount are unsigned, the following
3656 // gives the correct result even when the GC counter wraps around
3657 // UINT32_MAX since the last call to JS_GetGCParameter().
3658 return JS_GetGCParameter(nsJSRuntime::sRuntime
, JSGC_NUMBER
) -
3664 nsJSContext::MaybeCC(PRBool aHigherProbability
)
3666 ++sDelayedCCollectCount
;
3668 // Don't check suspected count if CC will be called anyway.
3669 if (sCCSuspectChanges
<= NS_MIN_SUSPECT_CHANGES
||
3670 GetGCRunsSinceLastCC() <= NS_MAX_GC_COUNT
) {
3672 PRTime now
= PR_Now();
3674 PRUint32 suspected
= nsCycleCollector_suspectedCount();
3676 printf("%u suspected objects (%lldms), sCCSuspectedCount %u\n",
3677 suspected
, (PR_Now() - now
) / PR_USEC_PER_MSEC
,
3680 // Update only when suspected count has increased.
3681 if (suspected
> sCCSuspectedCount
) {
3682 sCCSuspectChanges
+= (suspected
- sCCSuspectedCount
);
3683 sCCSuspectedCount
= suspected
;
3687 printf("sCCSuspectChanges %u, GC runs %u\n",
3688 sCCSuspectChanges
, GetGCRunsSinceLastCC());
3691 // Increase the probability also if the previous call to cycle collector
3692 // collected something.
3693 if (aHigherProbability
||
3694 sCollectedObjectsCounts
> NS_COLLECTED_OBJECTS_LIMIT
) {
3695 sDelayedCCollectCount
*= NS_PROBABILITY_MULTIPLIER
;
3696 } else if (!sUserIsActive
&& sCCSuspectChanges
> NS_MAX_SUSPECT_CHANGES
) {
3697 // If user is inactive and there are lots of new suspected objects,
3698 // increase the probability for cycle collection.
3699 sDelayedCCollectCount
+= (sCCSuspectChanges
/ NS_MAX_SUSPECT_CHANGES
);
3703 (sDelayedCCollectCount
> NS_MAX_DELAYED_CCOLLECT
) &&
3704 ((sCCSuspectChanges
> NS_MIN_SUSPECT_CHANGES
&&
3705 GetGCRunsSinceLastCC() > NS_MAX_GC_COUNT
) ||
3706 (sCCSuspectChanges
> NS_MAX_SUSPECT_CHANGES
))) {
3707 return IntervalCC();
3714 nsJSContext::CCIfUserInactive()
3716 if (sUserIsActive
) {
3725 nsJSContext::MaybeCCIfUserInactive()
3727 if (!sUserIsActive
) {
3734 nsJSContext::IntervalCC()
3736 if ((PR_Now() - sPreviousCCTime
) >=
3737 PRTime(NS_MIN_CC_INTERVAL
* PR_USEC_PER_MSEC
)) {
3738 nsJSContext::CC(nsnull
);
3742 printf("Running CC was delayed because of NS_MIN_CC_INTERVAL.\n");
3749 GCTimerFired(nsITimer
*aTimer
, void *aClosure
)
3751 NS_RELEASE(sGCTimer
);
3753 if (sPendingLoadCount
== 0 || sLoadInProgressGCTimer
) {
3754 sLoadInProgressGCTimer
= PR_FALSE
;
3756 // Reset sPendingLoadCount in case the timer that fired was a
3757 // timer we scheduled due to a normal GC timer firing while
3758 // documents were loading. If this happens we're waiting for a
3759 // document that is taking a long time to load, and we effectively
3760 // ignore the fact that the currently loading documents are still
3761 // loading and move on as if they weren't.
3762 sPendingLoadCount
= 0;
3764 nsJSContext::CCIfUserInactive();
3766 nsJSContext::FireGCTimer(PR_TRUE
);
3769 sReadyForGC
= PR_TRUE
;
3774 nsJSContext::LoadStart()
3776 ++sPendingLoadCount
;
3781 nsJSContext::LoadEnd()
3783 // sPendingLoadCount is not a well managed load counter (and doesn't
3784 // need to be), so make sure we don't make it wrap backwards here.
3785 if (sPendingLoadCount
> 0) {
3786 --sPendingLoadCount
;
3789 if (!sPendingLoadCount
&& sLoadInProgressGCTimer
) {
3791 NS_RELEASE(sGCTimer
);
3792 sLoadInProgressGCTimer
= PR_FALSE
;
3800 nsJSContext::FireGCTimer(PRBool aLoadInProgress
)
3803 // There's already a timer for GC'ing, just return
3807 CallCreateInstance("@mozilla.org/timer;1", &sGCTimer
);
3810 NS_WARNING("Failed to create timer");
3812 // Reset sLoadInProgressGCTimer since we're not able to fire the
3814 sLoadInProgressGCTimer
= PR_FALSE
;
3820 static PRBool first
= PR_TRUE
;
3822 sGCTimer
->InitWithFuncCallback(GCTimerFired
, nsnull
,
3823 first
? NS_FIRST_GC_DELAY
:
3824 aLoadInProgress
? NS_LOAD_IN_PROCESS_GC_DELAY
:
3826 nsITimer::TYPE_ONE_SHOT
);
3828 sLoadInProgressGCTimer
= aLoadInProgress
;
3834 DOMGCCallback(JSContext
*cx
, JSGCStatus status
)
3836 JSBool result
= gOldJSGCCallback
? gOldJSGCCallback(cx
, status
) : JS_TRUE
;
3838 if (status
== JSGC_BEGIN
&& !NS_IsMainThread())
3844 // Script object mananagement - note duplicate implementation
3845 // in nsJSRuntime below...
3847 nsJSContext::HoldScriptObject(void* aScriptObject
)
3849 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3850 if (! nsJSRuntime::sRuntime
) {
3851 NS_NOTREACHED("couldn't add GC root - no runtime");
3852 return NS_ERROR_FAILURE
;
3855 ::JS_LockGCThingRT(nsJSRuntime::sRuntime
, aScriptObject
);
3860 nsJSContext::DropScriptObject(void* aScriptObject
)
3862 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
3863 if (! nsJSRuntime::sRuntime
) {
3864 NS_NOTREACHED("couldn't remove GC root");
3865 return NS_ERROR_FAILURE
;
3868 ::JS_UnlockGCThingRT(nsJSRuntime::sRuntime
, aScriptObject
);
3873 nsJSContext::ReportPendingException()
3875 // set aside the frame chain, since it has nothing to do with the
3876 // exception we're reporting.
3877 if (mIsInitialized
&& ::JS_IsExceptionPending(mContext
)) {
3878 JSStackFrame
* frame
= JS_SaveFrameChain(mContext
);
3879 ::JS_ReportPendingException(mContext
);
3880 JS_RestoreFrameChain(mContext
, frame
);
3884 /**********************************************************************
3885 * nsJSRuntime implementation
3886 *********************************************************************/
3888 // QueryInterface implementation for nsJSRuntime
3889 NS_INTERFACE_MAP_BEGIN(nsJSRuntime
)
3890 NS_INTERFACE_MAP_ENTRY(nsIScriptRuntime
)
3891 NS_INTERFACE_MAP_END
3894 NS_IMPL_ADDREF(nsJSRuntime
)
3895 NS_IMPL_RELEASE(nsJSRuntime
)
3898 nsJSRuntime::CreateContext(nsIScriptContext
**aContext
)
3900 nsCOMPtr
<nsIScriptContext
> scriptContext
;
3902 *aContext
= new nsJSContext(sRuntime
);
3903 NS_ENSURE_TRUE(*aContext
, NS_ERROR_OUT_OF_MEMORY
);
3904 NS_ADDREF(*aContext
);
3909 nsJSRuntime::ParseVersion(const nsString
&aVersionStr
, PRUint32
*flags
)
3911 NS_PRECONDITION(flags
, "Null flags param?");
3912 JSVersion jsVersion
= JSVERSION_UNKNOWN
;
3913 if (aVersionStr
.Length() != 3 || aVersionStr
[0] != '1' || aVersionStr
[1] != '.')
3914 jsVersion
= JSVERSION_UNKNOWN
;
3915 else switch (aVersionStr
[2]) {
3916 case '0': jsVersion
= JSVERSION_1_0
; break;
3917 case '1': jsVersion
= JSVERSION_1_1
; break;
3918 case '2': jsVersion
= JSVERSION_1_2
; break;
3919 case '3': jsVersion
= JSVERSION_1_3
; break;
3920 case '4': jsVersion
= JSVERSION_1_4
; break;
3921 case '5': jsVersion
= JSVERSION_1_5
; break;
3922 case '6': jsVersion
= JSVERSION_1_6
; break;
3923 case '7': jsVersion
= JSVERSION_1_7
; break;
3924 case '8': jsVersion
= JSVERSION_1_8
; break;
3925 default: jsVersion
= JSVERSION_UNKNOWN
;
3927 *flags
= (PRUint32
)jsVersion
;
3933 nsJSRuntime::Startup()
3935 // initialize all our statics, so that we can restart XPCOM
3936 sDelayedCCollectCount
= 0;
3938 sUserIsActive
= PR_FALSE
;
3939 sPreviousCCTime
= PR_Now();
3940 sCollectedObjectsCounts
= 0;
3942 sCCSuspectChanges
= 0;
3943 sCCSuspectedCount
= 0;
3945 sReadyForGC
= PR_FALSE
;
3946 sLoadInProgressGCTimer
= PR_FALSE
;
3947 sPendingLoadCount
= 0;
3948 gNameSpaceManager
= nsnull
;
3949 sRuntimeService
= nsnull
;
3951 gOldJSGCCallback
= nsnull
;
3952 sIsInitialized
= PR_FALSE
;
3953 sDidShutdown
= PR_FALSE
;
3955 sSecurityManager
= nsnull
;
3956 gCollation
= nsnull
;
3960 MaxScriptRunTimePrefChangedCallback(const char *aPrefName
, void *aClosure
)
3962 // Default limit on script run time to 10 seconds. 0 means let
3963 // scripts run forever.
3964 PRBool isChromePref
=
3965 strcmp(aPrefName
, "dom.max_chrome_script_run_time") == 0;
3966 PRInt32 time
= nsContentUtils::GetIntPref(aPrefName
, isChromePref
? 20 : 10);
3970 // Let scripts run for a really, really long time.
3971 t
= LL_INIT(0x40000000, 0);
3973 t
= time
* PR_USEC_PER_SEC
;
3977 sMaxChromeScriptRunTime
= t
;
3979 sMaxScriptRunTime
= t
;
3986 ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3988 PRBool reportAll
= nsContentUtils::GetBoolPref(aPrefName
, PR_FALSE
);
3989 nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll
);
3994 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName
, void* aClosure
)
3996 PRInt32 highwatermark
= nsContentUtils::GetIntPref(aPrefName
, 32);
3998 if (highwatermark
>= 32) {
4000 * There are two ways to allocate memory in SpiderMonkey. One is
4001 * to use jsmalloc() and the other is to use GC-owned memory
4002 * (e.g. js_NewGCThing()).
4004 * In the browser, we don't cap the amount of GC-owned memory.
4006 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_MALLOC_BYTES
,
4007 128L * 1024L * 1024L);
4008 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_BYTES
,
4011 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_MALLOC_BYTES
,
4012 highwatermark
* 1024L * 1024L);
4013 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_MAX_BYTES
,
4014 highwatermark
* 1024L * 1024L);
4020 SetMemoryGCFrequencyPrefChangedCallback(const char* aPrefName
, void* aClosure
)
4022 PRInt32 triggerFactor
= nsContentUtils::GetIntPref(aPrefName
, 300);
4023 JS_SetGCParameter(nsJSRuntime::sRuntime
, JSGC_TRIGGER_FACTOR
, triggerFactor
);
4027 static JSPrincipals
*
4028 ObjectPrincipalFinder(JSContext
*cx
, JSObject
*obj
)
4030 if (!sSecurityManager
)
4033 nsCOMPtr
<nsIPrincipal
> principal
;
4035 sSecurityManager
->GetObjectPrincipal(cx
, obj
,
4036 getter_AddRefs(principal
));
4038 if (NS_FAILED(rv
) || !principal
) {
4042 JSPrincipals
*jsPrincipals
= nsnull
;
4043 principal
->GetJSPrincipals(cx
, &jsPrincipals
);
4045 // nsIPrincipal::GetJSPrincipals() returns a strong reference to the
4046 // JS principals, but the caller of this function expects a weak
4047 // reference. So we need to release here.
4049 JSPRINCIPALS_DROP(cx
, jsPrincipals
);
4051 return jsPrincipals
;
4055 DOMReadStructuredClone(JSContext
* cx
,
4056 JSStructuredCloneReader
* reader
,
4060 // We don't currently support any extensions to structured cloning.
4061 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
4066 DOMWriteStructuredClone(JSContext
* cx
,
4067 JSStructuredCloneWriter
* writer
,
4070 // We don't currently support any extensions to structured cloning.
4071 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
4076 DOMStructuredCloneError(JSContext
* cx
,
4079 // We don't currently support any extensions to structured cloning.
4080 nsDOMClassInfo::ThrowJSException(cx
, NS_ERROR_DOM_DATA_CLONE_ERR
);
4087 if (sIsInitialized
) {
4088 if (!nsContentUtils::XPConnect())
4089 return NS_ERROR_NOT_AVAILABLE
;
4094 nsresult rv
= CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
,
4096 NS_ENSURE_SUCCESS(rv
, rv
);
4098 rv
= CallGetService(kJSRuntimeServiceContractID
, &sRuntimeService
);
4099 // get the JSRuntime from the runtime svc, if possible
4100 NS_ENSURE_SUCCESS(rv
, rv
);
4102 rv
= sRuntimeService
->GetRuntime(&sRuntime
);
4103 NS_ENSURE_SUCCESS(rv
, rv
);
4105 // Let's make sure that our main thread is the same as the xpcom main thread.
4106 NS_ASSERTION(NS_IsMainThread(), "bad");
4108 NS_ASSERTION(!gOldJSGCCallback
,
4109 "nsJSRuntime initialized more than once");
4111 sSavedGCCount
= JS_GetGCParameter(nsJSRuntime::sRuntime
, JSGC_NUMBER
);
4113 // Save the old GC callback to chain to it, for GC-observing generality.
4114 gOldJSGCCallback
= ::JS_SetGCCallbackRT(sRuntime
, DOMGCCallback
);
4116 JSSecurityCallbacks
*callbacks
= JS_GetRuntimeSecurityCallbacks(sRuntime
);
4117 NS_ASSERTION(callbacks
, "SecMan should have set security callbacks!");
4119 callbacks
->findObjectPrincipals
= ObjectPrincipalFinder
;
4121 // Set up the structured clone callbacks.
4122 static JSStructuredCloneCallbacks cloneCallbacks
= {
4123 DOMReadStructuredClone
,
4124 DOMWriteStructuredClone
,
4125 DOMStructuredCloneError
4127 JS_SetStructuredCloneCallbacks(sRuntime
, &cloneCallbacks
);
4129 // Set these global xpconnect options...
4130 nsContentUtils::RegisterPrefCallback("dom.max_script_run_time",
4131 MaxScriptRunTimePrefChangedCallback
,
4133 MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull
);
4135 nsContentUtils::RegisterPrefCallback("dom.max_chrome_script_run_time",
4136 MaxScriptRunTimePrefChangedCallback
,
4138 MaxScriptRunTimePrefChangedCallback("dom.max_chrome_script_run_time",
4141 nsContentUtils::RegisterPrefCallback("dom.report_all_js_exceptions",
4142 ReportAllJSExceptionsPrefChangedCallback
,
4144 ReportAllJSExceptionsPrefChangedCallback("dom.report_all_js_exceptions",
4147 nsContentUtils::RegisterPrefCallback("javascript.options.mem.high_water_mark",
4148 SetMemoryHighWaterMarkPrefChangedCallback
,
4150 SetMemoryHighWaterMarkPrefChangedCallback("javascript.options.mem.high_water_mark",
4153 nsContentUtils::RegisterPrefCallback("javascript.options.mem.gc_frequency",
4154 SetMemoryGCFrequencyPrefChangedCallback
,
4156 SetMemoryGCFrequencyPrefChangedCallback("javascript.options.mem.gc_frequency",
4159 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
4161 return NS_ERROR_FAILURE
;
4162 nsIObserver
* activityObserver
= new nsUserActivityObserver();
4163 NS_ENSURE_TRUE(activityObserver
, NS_ERROR_OUT_OF_MEMORY
);
4164 obs
->AddObserver(activityObserver
, "user-interaction-inactive", PR_FALSE
);
4165 obs
->AddObserver(activityObserver
, "user-interaction-active", PR_FALSE
);
4166 obs
->AddObserver(activityObserver
, "xpcom-shutdown", PR_FALSE
);
4168 nsIObserver
* ccMemPressureObserver
= new nsCCMemoryPressureObserver();
4169 NS_ENSURE_TRUE(ccMemPressureObserver
, NS_ERROR_OUT_OF_MEMORY
);
4170 obs
->AddObserver(ccMemPressureObserver
, "memory-pressure", PR_FALSE
);
4172 sIsInitialized
= PR_TRUE
;
4178 nsScriptNameSpaceManager
*
4179 nsJSRuntime::GetNameSpaceManager()
4184 if (!gNameSpaceManager
) {
4185 gNameSpaceManager
= new nsScriptNameSpaceManager
;
4186 NS_ADDREF(gNameSpaceManager
);
4188 nsresult rv
= gNameSpaceManager
->Init();
4189 NS_ENSURE_SUCCESS(rv
, nsnull
);
4192 return gNameSpaceManager
;
4197 nsJSRuntime::Shutdown()
4200 // We're being shut down, if we have a GC timer scheduled, cancel
4201 // it. The DOM factory will do one final GC once it's shut down.
4205 NS_RELEASE(sGCTimer
);
4207 sLoadInProgressGCTimer
= PR_FALSE
;
4210 NS_IF_RELEASE(gNameSpaceManager
);
4212 if (!sContextCount
) {
4213 // We're being shutdown, and there are no more contexts
4214 // alive, release the JS runtime service and the security manager.
4216 if (sRuntimeService
&& sSecurityManager
) {
4217 JSSecurityCallbacks
*callbacks
= JS_GetRuntimeSecurityCallbacks(sRuntime
);
4219 NS_ASSERTION(callbacks
->findObjectPrincipals
== ObjectPrincipalFinder
,
4220 "Fighting over the findObjectPrincipals callback!");
4221 callbacks
->findObjectPrincipals
= NULL
;
4224 NS_IF_RELEASE(sRuntimeService
);
4225 NS_IF_RELEASE(sSecurityManager
);
4226 NS_IF_RELEASE(gCollation
);
4227 NS_IF_RELEASE(gDecoder
);
4230 sDidShutdown
= PR_TRUE
;
4233 // Script object mananagement - note duplicate implementation
4234 // in nsJSContext above...
4236 nsJSRuntime::HoldScriptObject(void* aScriptObject
)
4238 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
4240 NS_NOTREACHED("couldn't remove GC root - no runtime");
4241 return NS_ERROR_FAILURE
;
4244 ::JS_LockGCThingRT(sRuntime
, aScriptObject
);
4249 nsJSRuntime::DropScriptObject(void* aScriptObject
)
4251 NS_ASSERTION(sIsInitialized
, "runtime not initialized");
4253 NS_NOTREACHED("couldn't remove GC root");
4254 return NS_ERROR_FAILURE
;
4257 ::JS_UnlockGCThingRT(sRuntime
, aScriptObject
);
4261 // A factory for the runtime.
4262 nsresult
NS_CreateJSRuntime(nsIScriptRuntime
**aRuntime
)
4264 nsresult rv
= nsJSRuntime::Init();
4265 NS_ENSURE_SUCCESS(rv
, rv
);
4267 *aRuntime
= new nsJSRuntime();
4268 if (*aRuntime
== nsnull
)
4269 return NS_ERROR_OUT_OF_MEMORY
;
4270 NS_IF_ADDREF(*aRuntime
);
4274 // A fast-array class for JS. This class supports both nsIJSScriptArray and
4275 // nsIArray. If it is JS itself providing and consuming this class, all work
4276 // can be done via nsIJSScriptArray, and avoid the conversion of elements
4277 // to/from nsISupports.
4278 // When consumed by non-JS (eg, another script language), conversion is done
4280 class nsJSArgArray
: public nsIJSArgArray
, public nsIArray
{
4282 nsJSArgArray(JSContext
*aContext
, PRUint32 argc
, jsval
*argv
, nsresult
*prv
);
4285 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
4286 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray
,
4293 nsresult
GetArgs(PRUint32
*argc
, void **argv
);
4295 void ReleaseJSObjects();
4298 JSContext
*mContext
;
4303 nsJSArgArray::nsJSArgArray(JSContext
*aContext
, PRUint32 argc
, jsval
*argv
,
4309 // copy the array - we don't know its lifetime, and ours is tied to xpcom
4310 // refcounting. Alloc zero'd array so cleanup etc is safe.
4312 mArgv
= (jsval
*) PR_CALLOC(argc
* sizeof(jsval
));
4314 *prv
= NS_ERROR_OUT_OF_MEMORY
;
4319 // Callers are allowed to pass in a null argv even for argc > 0. They can
4320 // then use GetArgs to initialize the values.
4322 for (PRUint32 i
= 0; i
< argc
; ++i
)
4326 *prv
= argc
> 0 ? NS_HOLD_JS_OBJECTS(this, nsJSArgArray
) : NS_OK
;
4329 nsJSArgArray::~nsJSArgArray()
4335 nsJSArgArray::ReleaseJSObjects()
4338 NS_DROP_JS_OBJECTS(this, nsJSArgArray
);
4345 // QueryInterface implementation for nsJSArgArray
4346 NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSArgArray
)
4347 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsJSArgArray
)
4348 tmp
->ReleaseJSObjects();
4349 NS_IMPL_CYCLE_COLLECTION_ROOT_END
4350 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsJSArgArray
)
4351 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSArgArray
)
4352 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
4353 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
4355 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray
)
4356 jsval
*argv
= tmp
->mArgv
;
4359 for (end
= argv
+ tmp
->mArgc
; argv
< end
; ++argv
) {
4360 if (JSVAL_IS_GCTHING(*argv
))
4361 NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT
,
4362 JSVAL_TO_GCTHING(*argv
))
4365 NS_IMPL_CYCLE_COLLECTION_TRACE_END
4367 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray
)
4368 NS_INTERFACE_MAP_ENTRY(nsIArray
)
4369 NS_INTERFACE_MAP_ENTRY(nsIJSArgArray
)
4370 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSArgArray
)
4371 NS_INTERFACE_MAP_END
4373 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsJSArgArray
, nsIJSArgArray
)
4374 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsJSArgArray
, nsIJSArgArray
)
4377 nsJSArgArray::GetArgs(PRUint32
*argc
, void **argv
)
4380 NS_WARNING("nsJSArgArray has no argv!");
4381 return NS_ERROR_UNEXPECTED
;
4383 *argv
= (void *)mArgv
;
4389 NS_IMETHODIMP
nsJSArgArray::GetLength(PRUint32
*aLength
)
4395 /* void queryElementAt (in unsigned long index, in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
4396 NS_IMETHODIMP
nsJSArgArray::QueryElementAt(PRUint32 index
, const nsIID
& uuid
, void * *result
)
4400 return NS_ERROR_INVALID_ARG
;
4402 if (uuid
.Equals(NS_GET_IID(nsIVariant
)) || uuid
.Equals(NS_GET_IID(nsISupports
))) {
4403 return nsContentUtils::XPConnect()->JSToVariant(mContext
, mArgv
[index
],
4404 (nsIVariant
**)result
);
4406 NS_WARNING("nsJSArgArray only handles nsIVariant");
4407 return NS_ERROR_NO_INTERFACE
;
4410 /* unsigned long indexOf (in unsigned long startIndex, in nsISupports element); */
4411 NS_IMETHODIMP
nsJSArgArray::IndexOf(PRUint32 startIndex
, nsISupports
*element
, PRUint32
*_retval
)
4413 return NS_ERROR_NOT_IMPLEMENTED
;
4416 /* nsISimpleEnumerator enumerate (); */
4417 NS_IMETHODIMP
nsJSArgArray::Enumerate(nsISimpleEnumerator
**_retval
)
4419 return NS_ERROR_NOT_IMPLEMENTED
;
4422 // The factory function
4423 nsresult
NS_CreateJSArgv(JSContext
*aContext
, PRUint32 argc
, void *argv
,
4427 nsJSArgArray
*ret
= new nsJSArgArray(aContext
, argc
,
4428 static_cast<jsval
*>(argv
), &rv
);
4430 return NS_ERROR_OUT_OF_MEMORY
;
4431 if (NS_FAILED(rv
)) {
4435 return ret
->QueryInterface(NS_GET_IID(nsIArray
), (void **)aArray
);