1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #define __STDC_LIMIT_MACROS
58 #include "jswrapper.h"
62 #include "jsbuiltins.h"
74 #include "jsreflect.h"
78 #include "jstypedarray.h"
86 #ifdef JSDEBUGGER_JAVA_UI
88 #endif /* JSDEBUGGER_JAVA_UI */
89 #ifdef JSDEBUGGER_C_UI
91 #endif /* JSDEBUGGER_C_UI */
92 #endif /* JSDEBUGGER */
94 #include "jsworkers.h"
96 #include "jsinterpinlines.h"
97 #include "jsobjinlines.h"
98 #include "jsscriptinlines.h"
102 #include <sys/types.h>
103 #include <sys/wait.h>
106 #if defined(XP_WIN) || defined(XP_OS2)
107 #include <io.h> /* for isatty() */
116 typedef enum JSShellExitCode
{
117 EXITCODE_RUNTIME_ERROR
= 3,
118 EXITCODE_FILE_NOT_FOUND
= 4,
119 EXITCODE_OUT_OF_MEMORY
= 5,
123 size_t gStackChunkSize
= 8192;
125 /* Assume that we can not use more than 5e5 bytes of C stack by default. */
126 #if (defined(DEBUG) && defined(__SUNPRO_CC)) || defined(JS_CPU_SPARC)
127 /* Sun compiler uses larger stack space for js_Interpret() with debug
128 Use a bigger gMaxStackSize to make "make check" happy. */
129 #define DEFAULT_MAX_STACK_SIZE 5000000
131 #define DEFAULT_MAX_STACK_SIZE 500000
134 size_t gMaxStackSize
= DEFAULT_MAX_STACK_SIZE
;
138 static PRUintn gStackBaseThreadIndex
;
140 static jsuword gStackBase
;
143 static size_t gScriptStackQuota
= JS_DEFAULT_SCRIPT_STACK_QUOTA
;
146 * Limit the timeout to 30 minutes to prevent an overflow on platfoms
147 * that represent the time internally in microseconds using 32-bit int.
149 static jsdouble MAX_TIMEOUT_INTERVAL
= 1800.0;
150 static jsdouble gTimeoutInterval
= -1.0;
151 static volatile bool gCanceled
= false;
153 static bool enableTraceJit
= false;
154 static bool enableMethodJit
= false;
155 static bool enableProfiling
= false;
157 static bool printTiming
= false;
160 SetTimeoutValue(JSContext
*cx
, jsdouble t
);
163 InitWatchdog(JSRuntime
*rt
);
169 ScheduleWatchdog(JSRuntime
*rt
, jsdouble t
);
172 CancelExecution(JSRuntime
*rt
);
175 * Watchdog thread state.
179 static PRLock
*gWatchdogLock
= NULL
;
180 static PRCondVar
*gWatchdogWakeup
= NULL
;
181 static PRThread
*gWatchdogThread
= NULL
;
182 static bool gWatchdogHasTimeout
= false;
183 static PRIntervalTime gWatchdogTimeout
= 0;
185 static PRCondVar
*gSleepWakeup
= NULL
;
189 static JSRuntime
*gRuntime
= NULL
;
194 JSBool gQuitting
= JS_FALSE
;
195 FILE *gErrFile
= NULL
;
196 FILE *gOutFile
= NULL
;
198 JSObject
*gWorkers
= NULL
;
199 js::workers::ThreadPool
*gWorkerThreadPool
= NULL
;
202 static JSBool reportWarnings
= JS_TRUE
;
203 static JSBool compileOnly
= JS_FALSE
;
205 typedef enum JSShellErrNum
{
206 #define MSG_DEF(name, number, count, exception, format) \
208 #include "jsshell.msg"
215 NewContext(JSRuntime
*rt
);
218 DestroyContext(JSContext
*cx
, bool withGC
);
220 static const JSErrorFormatString
*
221 my_GetErrorMessage(void *userRef
, const char *locale
, const uintN errorNumber
);
224 split_setup(JSContext
*cx
, JSBool evalcx
);
228 JS_EXTERN_API(char) *readline(const char *prompt
);
229 JS_EXTERN_API(void) add_history(char *line
);
234 ReportException(JSContext
*cx
)
236 if (JS_IsExceptionPending(cx
)) {
237 if (!JS_ReportPendingException(cx
))
238 JS_ClearPendingException(cx
);
244 ToString(JSContext
*aCx
, jsval v
, JSBool aThrow
= JS_FALSE
)
245 : cx(aCx
), mThrow(aThrow
)
247 mStr
= JS_ValueToString(cx
, v
);
248 if (!aThrow
&& !mStr
)
250 JS_AddNamedStringRoot(cx
, &mStr
, "Value ToString helper");
253 JS_RemoveStringRoot(cx
, &mStr
);
255 JSBool
threw() { return !mStr
; }
256 jsval
getJSVal() { return STRING_TO_JSVAL(mStr
); }
257 const char *getBytes() {
258 if (mStr
&& (mBytes
.ptr() || mBytes
.encode(cx
, mStr
)))
260 return "(error converting value)";
266 JSAutoByteString mBytes
;
269 class IdToString
: public ToString
{
271 IdToString(JSContext
*cx
, jsid id
, JSBool aThrow
= JS_FALSE
)
272 : ToString(cx
, IdToJsval(id
), aThrow
)
277 GetLine(FILE *file
, const char * prompt
)
283 * Use readline only if file is stdin, because there's no way to specify
284 * another handle. Are other filehandles interactive?
287 char *linep
= readline(prompt
);
289 * We set it to zero to avoid complaining about inappropriate ioctl
290 * for device in the case of EOF. Looks like errno == 251 if line is
291 * finished with EOF and errno == 25 (EINVAL on Mac) if there is
292 * nothing left to read.
294 if (errno
== 251 || errno
== 25 || errno
== EINVAL
)
298 if (linep
[0] != '\0')
304 if (*prompt
!= '\0') {
305 fprintf(gOutFile
, "%s", prompt
);
309 buffer
= (char *) malloc(size
);
312 char *current
= buffer
;
313 while (fgets(current
, size
- len
, file
)) {
314 len
+= strlen(current
);
315 char *t
= buffer
+ len
- 1;
317 /* Line was read. We remove '\n' and exit. */
321 if (len
+ 1 == size
) {
323 char *tmp
= (char *) realloc(buffer
, size
);
330 current
= buffer
+ len
;
332 if (len
&& !ferror(file
))
339 * State to store as JSContext private.
341 * We declare such timestamp as volatile as they are updated in the operation
342 * callback without taking any locks. Any possible race can only lead to more
343 * frequent callback calls. This is safe as the callback does everything based
346 struct JSShellContextData
{
347 volatile JSIntervalTime startTime
;
350 static JSShellContextData
*
353 /* Prevent creation of new contexts after we have been canceled. */
357 JSShellContextData
*data
= (JSShellContextData
*)
358 calloc(sizeof(JSShellContextData
), 1);
361 data
->startTime
= js_IntervalNow();
365 static inline JSShellContextData
*
366 GetContextData(JSContext
*cx
)
368 JSShellContextData
*data
= (JSShellContextData
*) JS_GetContextPrivate(cx
);
375 ShellOperationCallback(JSContext
*cx
)
380 JS_ClearPendingException(cx
);
385 SetContextOptions(JSContext
*cx
)
387 JS_SetNativeStackQuota(cx
, gMaxStackSize
);
388 JS_SetScriptStackQuota(cx
, gScriptStackQuota
);
389 JS_SetOperationCallback(cx
, ShellOperationCallback
);
397 Process(JSContext
*cx
, JSObject
*obj
, char *filename
, JSBool forceTTY
)
410 if (forceTTY
|| !filename
|| strcmp(filename
, "-") == 0) {
413 file
= fopen(filename
, "r");
415 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
416 JSSMSG_CANT_OPEN
, filename
, strerror(errno
));
417 gExitCode
= EXITCODE_FILE_NOT_FOUND
;
422 SetContextOptions(cx
);
425 /* windows mobile (and possibly other os's) does not have a TTY */
426 if (!forceTTY
&& !isatty(fileno(file
)))
430 * It's not interactive - just execute it.
432 * Support the UNIX #! shell hack; gobble the first line if it starts
433 * with '#'. TODO - this isn't quite compatible with sharp variables,
434 * as a legal js program (using sharp variables) might start with '#'.
435 * But that would require multi-character lookahead.
437 int ch
= fgetc(file
);
439 while((ch
= fgetc(file
)) != EOF
) {
440 if (ch
== '\n' || ch
== '\r')
446 int64 t1
= PRMJ_Now();
447 oldopts
= JS_GetOptions(cx
);
448 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
| JSOPTION_NO_SCRIPT_RVAL
);
449 script
= JS_CompileFileHandle(cx
, obj
, filename
, file
);
450 JS_SetOptions(cx
, oldopts
);
451 if (script
&& !compileOnly
) {
452 (void)JS_ExecuteScript(cx
, obj
, script
, NULL
);
453 int64 t2
= PRMJ_Now() - t1
;
455 printf("runtime = %.3f ms\n", double(t2
) / PRMJ_USEC_PER_MSEC
);
461 /* It's an interactive filehandle; drop into read-eval-print loop. */
465 size
= 0; /* assign here to avoid warnings */
468 * Accumulate lines until we get a 'compilable unit' - one that either
469 * generates an error (before running out of source) or that compiles
470 * cleanly. This should be whenever we get a complete statement that
471 * coincides with the end of a line.
474 size_t len
= 0; /* initialize to avoid warnings */
476 ScheduleWatchdog(cx
->runtime
, -1);
482 JSAutoSuspendRequest
suspended(cx
);
483 line
= GetLine(file
, startline
== lineno
? "js> " : "");
487 JS_ReportError(cx
, strerror(errno
));
496 len
= strlen(buffer
);
500 * len + 1 is required to store '\n' in the end of line.
502 size_t newlen
= strlen(line
) + (len
? len
+ 1 : 0);
503 if (newlen
+ 1 > size
) {
504 size
= newlen
+ 1 > size
* 2 ? newlen
+ 1 : size
* 2;
505 char *newBuf
= (char *) realloc(buffer
, size
);
509 JS_ReportOutOfMemory(cx
);
514 char *current
= buffer
+ len
;
515 if (startline
!= lineno
)
517 strcpy(current
, line
);
522 if (!ScheduleWatchdog(cx
->runtime
, gTimeoutInterval
)) {
526 } while (!JS_BufferIsCompilableUnit(cx
, obj
, buffer
, len
));
528 if (hitEOF
&& !buffer
)
531 /* Clear any pending exception from previous failed compiles. */
532 JS_ClearPendingException(cx
);
534 /* Even though we're interactive, we have a compile-n-go opportunity. */
535 oldopts
= JS_GetOptions(cx
);
537 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
);
538 script
= JS_CompileScript(cx
, obj
, buffer
, len
, "typein",
541 JS_SetOptions(cx
, oldopts
);
543 if (script
&& !compileOnly
) {
544 ok
= JS_ExecuteScript(cx
, obj
, script
, &result
);
545 if (ok
&& !JSVAL_IS_VOID(result
)) {
546 str
= JS_ValueToSource(cx
, result
);
549 JSAutoByteString
bytes(cx
, str
);
552 fprintf(gOutFile
, "%s\n", bytes
.ptr());
557 } while (!hitEOF
&& !gQuitting
);
560 fprintf(gOutFile
, "\n");
570 fprintf(gErrFile
, "%s\n", JS_GetImplementationVersion());
571 fprintf(gErrFile
, "usage: js [options] [scriptfile] [scriptarg...]\n"
573 " -h Display this information\n"
574 " -z Create a split global object\n"
575 " Warning: this option is probably not useful\n"
576 " -P Deeply freeze the global object prototype\n"
577 " -s Toggle JSOPTION_STRICT flag\n"
578 " -w Report strict warnings\n"
579 " -W Do not report strict warnings\n"
580 " -x Toggle JSOPTION_XML flag\n"
581 " -C Compile-only; do not execute\n"
582 " -i Enable interactive read-eval-print loop\n"
583 " -j Enable the TraceMonkey tracing JIT\n"
584 " -m Enable the JaegerMonkey method JIT\n"
585 " -a Always method JIT, ignore internal tuning\n"
586 " This only has effect with -m\n"
587 " -p Enable loop profiling for TraceMonkey\n"
588 " -d Enable debug mode\n"
589 " -b Print timing statistics\n"
590 " -t <timeout> Interrupt long-running execution after <timeout> seconds, where\n"
591 " <timeout> <= 1800.0. Negative values indicate no timeout (default).\n"
592 " -c <size> Suggest stack chunk size of <size> bytes. Default is 8192.\n"
593 " Warning: this option is currently ignored.\n"
594 " -o <option> Enable a context option flag by name\n"
595 " Possible values:\n"
596 " anonfunfix: JSOPTION_ANONFUNFIX\n"
597 " atline: JSOPTION_ATLINE\n"
598 " tracejit: JSOPTION_JIT\n"
599 " methodjit: JSOPTION_METHODJIT\n"
600 " relimit: JSOPTION_RELIMIT\n"
601 " strict: JSOPTION_STRICT\n"
602 " werror: JSOPTION_WERROR\n"
603 " xml: JSOPTION_XML\n"
604 " -v <version> Set the JavaScript language version\n"
605 " Possible values:\n"
606 " 150: JavaScript 1.5\n"
607 " 160: JavaScript 1.6\n"
608 " 170: JavaScript 1.7\n"
609 " 180: JavaScript 1.8\n"
610 " 185: JavaScript 1.8.5 (default)\n"
611 " -f <file> Load and execute JavaScript source <file>\n"
612 " Note: this option switches to non-interactive mode.\n"
613 " -e <source> Execute JavaScript <source>\n"
614 " Note: this option switches to non-interactive mode.\n"
615 " -S <size> Set the maximum size of the stack to <size> bytes\n"
616 " Default is %u.\n", DEFAULT_MAX_STACK_SIZE
);
618 fprintf(gErrFile
, " -g <n> Sleep for <n> seconds before starting (default: 0)\n");
621 fprintf(gErrFile
, " -Z <n> Toggle GC zeal: low if <n> is 0 (default), high if non-zero\n");
624 fprintf(gErrFile
, " -T Start TraceVis\n");
630 * JSContext option name to flag map. The option names are in alphabetical
631 * order for better reporting.
633 static const struct {
637 {"anonfunfix", JSOPTION_ANONFUNFIX
},
638 {"atline", JSOPTION_ATLINE
},
639 {"jitprofiling", JSOPTION_PROFILING
},
640 {"tracejit", JSOPTION_JIT
},
641 {"methodjit", JSOPTION_METHODJIT
},
642 {"methodjit_always",JSOPTION_METHODJIT_ALWAYS
},
643 {"relimit", JSOPTION_RELIMIT
},
644 {"strict", JSOPTION_STRICT
},
645 {"werror", JSOPTION_WERROR
},
646 {"xml", JSOPTION_XML
},
650 MapContextOptionNameToFlag(JSContext
* cx
, const char* name
)
652 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(js_options
); ++i
) {
653 if (strcmp(name
, js_options
[i
].name
) == 0)
654 return js_options
[i
].flag
;
657 char* msg
= JS_sprintf_append(NULL
,
658 "unknown option name '%s'."
659 " The valid names are ", name
);
660 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(js_options
); ++i
) {
663 msg
= JS_sprintf_append(msg
, "%s%s", js_options
[i
].name
,
664 (i
+ 2 < JS_ARRAY_LENGTH(js_options
)
666 : i
+ 2 == JS_ARRAY_LENGTH(js_options
)
671 JS_ReportOutOfMemory(cx
);
673 JS_ReportError(cx
, msg
);
679 extern JSClass global_class
;
681 #if defined(JS_TRACER) && defined(DEBUG)
683 extern struct JSClass jitstats_class
;
684 void InitJITStatsClass(JSContext
*cx
, JSObject
*glob
);
689 ProcessArgs(JSContext
*cx
, JSObject
*obj
, char **argv
, int argc
)
693 char *filename
= NULL
;
694 JSBool isInteractive
= JS_TRUE
;
695 JSBool forceTTY
= JS_FALSE
;
698 * Scan past all optional arguments so we can create the arguments object
699 * before processing any -f options, which must interleave properly with
700 * -v and -w options. This requires two passes, and without getopt, we'll
701 * have to keep the option logic here and in the second for loop in sync.
703 for (i
= 0; i
< argc
; i
++) {
704 if (argv
[i
][0] != '-' || argv
[i
][1] == '\0') {
708 switch (argv
[i
][1]) {
729 * Create arguments early and define it to root it, so it's safe from any
730 * GC calls nested below, and so it is available to -f <file> arguments.
732 argsObj
= JS_NewArrayObject(cx
, 0, NULL
);
735 if (!JS_DefineProperty(cx
, obj
, "arguments", OBJECT_TO_JSVAL(argsObj
),
741 for (j
= 0; j
< length
; j
++) {
742 JSString
*str
= JS_NewStringCopyZ(cx
, argv
[i
++]);
745 if (!JS_DefineElement(cx
, argsObj
, j
, STRING_TO_JSVAL(str
),
746 NULL
, NULL
, JSPROP_ENUMERATE
)) {
751 for (i
= 0; i
< argc
; i
++) {
752 if (argv
[i
][0] != '-' || argv
[i
][1] == '\0') {
753 filename
= argv
[i
++];
754 isInteractive
= JS_FALSE
;
758 switch (argv
[i
][1]) {
763 JS_SetVersion(cx
, (JSVersion
) atoi(argv
[i
]));
770 JS_SetGCZeal(cx
, !!(atoi(argv
[i
])));
775 reportWarnings
= JS_TRUE
;
779 reportWarnings
= JS_FALSE
;
783 JS_ToggleOptions(cx
, JSOPTION_STRICT
);
787 JS_ToggleOptions(cx
, JSOPTION_RELIMIT
);
791 JS_ToggleOptions(cx
, JSOPTION_XML
);
799 enableTraceJit
= !enableTraceJit
;
800 JS_ToggleOptions(cx
, JSOPTION_JIT
);
801 #if defined(JS_TRACER) && defined(DEBUG)
802 js::InitJITStatsClass(cx
, JS_GetGlobalObject(cx
));
803 JS_DefineObject(cx
, JS_GetGlobalObject(cx
), "tracemonkey",
804 &js::jitstats_class
, NULL
, 0);
809 enableMethodJit
= !enableMethodJit
;
810 JS_ToggleOptions(cx
, JSOPTION_METHODJIT
);
814 JS_ToggleOptions(cx
, JSOPTION_METHODJIT_ALWAYS
);
818 enableProfiling
= !enableProfiling
;
819 JS_ToggleOptions(cx
, JSOPTION_PROFILING
);
827 uint32 flag
= MapContextOptionNameToFlag(cx
, argv
[i
]);
830 JS_ToggleOptions(cx
, flag
);
834 if (JS_GET_CLASS(cx
, JS_GetPrototype(cx
, obj
)) != &global_class
) {
837 if (!JS_DeepFreezeObject(cx
, obj
))
839 gobj
= JS_NewGlobalObject(cx
, &global_class
);
842 if (!JS_SetPrototype(cx
, gobj
, obj
))
844 JS_SetParent(cx
, gobj
, NULL
);
845 JS_SetGlobalObject(cx
, gobj
);
854 if (!SetTimeoutValue(cx
, atof(argv
[i
])))
860 /* set stack chunk size */
861 gStackChunkSize
= atoi(argv
[++i
]);
868 Process(cx
, obj
, argv
[i
], JS_FALSE
);
873 * XXX: js -f foo.js should interpret foo.js and then
874 * drop into interactive mode, but that breaks the test
875 * harness. Just execute foo.js for now.
877 isInteractive
= JS_FALSE
;
887 /* Pass a filename of -e to imitate PERL */
888 JS_EvaluateScript(cx
, obj
, argv
[i
], strlen(argv
[i
]),
891 isInteractive
= JS_FALSE
;
896 compileOnly
= JS_TRUE
;
897 isInteractive
= JS_FALSE
;
901 isInteractive
= forceTTY
= JS_TRUE
;
908 /* Set maximum stack size. */
909 gMaxStackSize
= atoi(argv
[i
]);
913 JS_SetDebugMode(cx
, JS_TRUE
);
917 obj
= split_setup(cx
, JS_FALSE
);
926 StartTraceVis(argv
[i
]);
934 PR_Sleep(PR_SecondsToInterval(atoi(argv
[i
])));
943 if (filename
|| isInteractive
)
944 Process(cx
, obj
, filename
, forceTTY
);
949 Version(JSContext
*cx
, uintN argc
, jsval
*vp
)
951 jsval
*argv
= JS_ARGV(cx
, vp
);
952 if (argc
> 0 && JSVAL_IS_INT(argv
[0]))
953 *vp
= INT_TO_JSVAL(JS_SetVersion(cx
, (JSVersion
) JSVAL_TO_INT(argv
[0])));
955 *vp
= INT_TO_JSVAL(JS_GetVersion(cx
));
960 RevertVersion(JSContext
*cx
, uintN argc
, jsval
*vp
)
962 js_RevertVersion(cx
);
963 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
968 Options(JSContext
*cx
, uintN argc
, jsval
*vp
)
976 jsval
*argv
= JS_ARGV(cx
, vp
);
977 for (uintN i
= 0; i
< argc
; i
++) {
978 str
= JS_ValueToString(cx
, argv
[i
]);
981 argv
[i
] = STRING_TO_JSVAL(str
);
982 JSAutoByteString
opt(cx
, str
);
985 flag
= MapContextOptionNameToFlag(cx
, opt
.ptr());
990 optset
= JS_ToggleOptions(cx
, optset
);
994 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(js_options
); i
++) {
995 if (js_options
[i
].flag
& optset
) {
997 names
= JS_sprintf_append(names
, "%s%s",
998 names
? "," : "", js_options
[i
].name
);
1006 JS_ReportOutOfMemory(cx
);
1009 str
= JS_NewStringCopyZ(cx
, names
);
1013 *vp
= STRING_TO_JSVAL(str
);
1018 Load(JSContext
*cx
, uintN argc
, jsval
*vp
)
1025 JSObject
*thisobj
= JS_THIS_OBJECT(cx
, vp
);
1029 jsval
*argv
= JS_ARGV(cx
, vp
);
1030 for (i
= 0; i
< argc
; i
++) {
1031 str
= JS_ValueToString(cx
, argv
[i
]);
1034 argv
[i
] = STRING_TO_JSVAL(str
);
1035 JSAutoByteString
filename(cx
, str
);
1039 oldopts
= JS_GetOptions(cx
);
1040 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
| JSOPTION_NO_SCRIPT_RVAL
);
1041 script
= JS_CompileFile(cx
, thisobj
, filename
.ptr());
1044 JS_SetOptions(cx
, oldopts
);
1045 if (!compileOnly
&& !JS_ExecuteScript(cx
, thisobj
, script
, NULL
))
1053 Evaluate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1055 if (argc
!= 1 || !JSVAL_IS_STRING(JS_ARGV(cx
, vp
)[0])) {
1056 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1057 (argc
!= 1) ? JSSMSG_NOT_ENOUGH_ARGS
: JSSMSG_INVALID_ARGS
,
1062 JSString
*code
= JSVAL_TO_STRING(JS_ARGV(cx
, vp
)[0]);
1065 const jschar
*codeChars
= JS_GetStringCharsAndLength(cx
, code
, &codeLength
);
1069 JSObject
*thisobj
= JS_THIS_OBJECT(cx
, vp
);
1073 if ((JS_GET_CLASS(cx
, thisobj
)->flags
& JSCLASS_IS_GLOBAL
) != JSCLASS_IS_GLOBAL
) {
1074 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_UNEXPECTED_TYPE
,
1075 "this-value passed to evaluate()", "not a global object");
1079 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1080 return JS_EvaluateUCScript(cx
, thisobj
, codeChars
, codeLength
, "@evaluate", 0, NULL
);
1084 FileAsString(JSContext
*cx
, const char *pathname
)
1087 JSString
*str
= NULL
;
1091 file
= fopen(pathname
, "rb");
1093 JS_ReportError(cx
, "can't open %s: %s", pathname
, strerror(errno
));
1097 if (fseek(file
, 0, SEEK_END
) == EOF
) {
1098 JS_ReportError(cx
, "can't seek end of %s", pathname
);
1101 if (fseek(file
, 0, SEEK_SET
) == EOF
) {
1102 JS_ReportError(cx
, "can't seek start of %s", pathname
);
1104 buf
= (char*) JS_malloc(cx
, len
+ 1);
1106 cc
= fread(buf
, 1, len
, file
);
1108 JS_ReportError(cx
, "can't read %s: %s", pathname
,
1109 (ptrdiff_t(cc
) < 0) ? strerror(errno
) : "short read");
1112 str
= JS_NewStringCopyN(cx
, buf
, len
);
1124 * Function to run scripts and return compilation + execution time. Semantics
1125 * are closely modelled after the equivalent function in WebKit, as this is used
1126 * to produce benchmark timings by SunSpider.
1129 Run(JSContext
*cx
, uintN argc
, jsval
*vp
)
1132 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_INVALID_ARGS
, "run");
1136 JSObject
*thisobj
= JS_THIS_OBJECT(cx
, vp
);
1140 jsval
*argv
= JS_ARGV(cx
, vp
);
1141 JSString
*str
= JS_ValueToString(cx
, argv
[0]);
1144 argv
[0] = STRING_TO_JSVAL(str
);
1145 JSAutoByteString
filename(cx
, str
);
1149 const jschar
*ucbuf
= NULL
;
1151 str
= FileAsString(cx
, filename
.ptr());
1153 ucbuf
= JS_GetStringCharsAndLength(cx
, str
, &buflen
);
1157 JS::Anchor
<JSString
*> a_str(str
);
1158 uint32 oldopts
= JS_GetOptions(cx
);
1159 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
| JSOPTION_NO_SCRIPT_RVAL
);
1161 int64 startClock
= PRMJ_Now();
1162 JSScript
*script
= JS_CompileUCScript(cx
, thisobj
, ucbuf
, buflen
, filename
.ptr(), 1);
1163 JS_SetOptions(cx
, oldopts
);
1167 JSBool ok
= JS_ExecuteScript(cx
, thisobj
, script
, NULL
);
1168 int64 endClock
= PRMJ_Now();
1169 JS_DestroyScript(cx
, script
);
1173 JS_SET_RVAL(cx
, vp
, DOUBLE_TO_JSVAL((endClock
- startClock
) / double(PRMJ_USEC_PER_MSEC
)));
1178 * function readline()
1179 * Provides a hook for scripts to read a line from stdin.
1182 ReadLine(JSContext
*cx
, uintN argc
, jsval
*vp
)
1187 size_t bufsize
, buflength
, gotlength
;
1194 buf
= (char *) JS_malloc(cx
, bufsize
);
1198 sawNewline
= JS_FALSE
;
1200 js_fgets(buf
+ buflength
, bufsize
- buflength
, from
)) > 0) {
1201 buflength
+= gotlength
;
1204 if (buf
[buflength
- 1] == '\n') {
1205 buf
[buflength
- 1] = '\0';
1206 sawNewline
= JS_TRUE
;
1208 } else if (buflength
< bufsize
- 1) {
1212 /* Else, grow our buffer for another pass. */
1214 if (bufsize
> buflength
) {
1215 tmp
= (char *) JS_realloc(cx
, buf
, bufsize
);
1217 JS_ReportOutOfMemory(cx
);
1229 /* Treat the empty string specially. */
1230 if (buflength
== 0) {
1231 *vp
= feof(from
) ? JSVAL_NULL
: JS_GetEmptyStringValue(cx
);
1236 /* Shrink the buffer to the real size. */
1237 tmp
= (char *) JS_realloc(cx
, buf
, buflength
);
1246 * Turn buf into a JSString. Note that buflength includes the trailing null
1249 str
= JS_NewStringCopyN(cx
, buf
, sawNewline
? buflength
- 1 : buflength
);
1254 *vp
= STRING_TO_JSVAL(str
);
1259 PutStr(JSContext
*cx
, uintN argc
, jsval
*vp
)
1266 argv
= JS_ARGV(cx
, vp
);
1267 str
= JS_ValueToString(cx
, argv
[0]);
1270 bytes
= JS_EncodeString(cx
, str
);
1273 fputs(bytes
, gOutFile
);
1278 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1283 Now(JSContext
*cx
, uintN argc
, jsval
*vp
)
1285 jsdouble now
= PRMJ_Now() / double(PRMJ_USEC_PER_MSEC
);
1286 JS_SET_RVAL(cx
, vp
, DOUBLE_TO_JSVAL(now
));
1291 Print(JSContext
*cx
, uintN argc
, jsval
*vp
)
1298 argv
= JS_ARGV(cx
, vp
);
1299 for (i
= 0; i
< argc
; i
++) {
1300 str
= JS_ValueToString(cx
, argv
[i
]);
1303 bytes
= JS_EncodeString(cx
, str
);
1306 fprintf(gOutFile
, "%s%s", i
? " " : "", bytes
);
1310 fputc('\n', gOutFile
);
1313 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1318 Help(JSContext
*cx
, uintN argc
, jsval
*vp
);
1321 Quit(JSContext
*cx
, uintN argc
, jsval
*vp
)
1323 JS_ConvertArguments(cx
, argc
, JS_ARGV(cx
, vp
), "/ i", &gExitCode
);
1325 gQuitting
= JS_TRUE
;
1326 #ifdef JS_THREADSAFE
1327 if (gWorkerThreadPool
)
1328 js::workers::terminateAll(JS_GetRuntime(cx
), gWorkerThreadPool
);
1334 ToSource(JSContext
*cx
, jsval
*vp
, JSAutoByteString
*bytes
)
1336 JSString
*str
= JS_ValueToSource(cx
, *vp
);
1338 *vp
= STRING_TO_JSVAL(str
);
1339 if (bytes
->encode(cx
, str
))
1340 return bytes
->ptr();
1342 JS_ClearPendingException(cx
);
1343 return "<<error converting value to string>>";
1347 AssertEq(JSContext
*cx
, uintN argc
, jsval
*vp
)
1349 if (!(argc
== 2 || (argc
== 3 && JSVAL_IS_STRING(JS_ARGV(cx
, vp
)[2])))) {
1350 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1352 ? JSSMSG_NOT_ENOUGH_ARGS
1354 ? JSSMSG_INVALID_ARGS
1355 : JSSMSG_TOO_MANY_ARGS
,
1360 jsval
*argv
= JS_ARGV(cx
, vp
);
1362 if (!JS_SameValue(cx
, argv
[0], argv
[1], &same
))
1365 JSAutoByteString bytes0
, bytes1
;
1366 const char *actual
= ToSource(cx
, &argv
[0], &bytes0
);
1367 const char *expected
= ToSource(cx
, &argv
[1], &bytes1
);
1369 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_ASSERT_EQ_FAILED
,
1372 JSAutoByteString
bytes2(cx
, JSVAL_TO_STRING(argv
[2]));
1375 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_ASSERT_EQ_FAILED_MSG
,
1376 actual
, expected
, bytes2
.ptr());
1380 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1385 AssertJit(JSContext
*cx
, uintN argc
, jsval
*vp
)
1388 if (JS_GetOptions(cx
) & JSOPTION_METHODJIT
) {
1389 if (!cx
->fp()->script()->getJIT(cx
->fp()->isConstructing())) {
1390 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_ASSERT_JIT_FAILED
);
1396 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1401 GC(JSContext
*cx
, uintN argc
, jsval
*vp
)
1403 size_t preBytes
= cx
->runtime
->gcBytes
;
1407 JS_snprintf(buf
, sizeof(buf
), "before %lu, after %lu, break %08lx\n",
1408 (unsigned long)preBytes
, (unsigned long)cx
->runtime
->gcBytes
,
1410 (unsigned long)sbrk(0)
1415 *vp
= STRING_TO_JSVAL(JS_NewStringCopyZ(cx
, buf
));
1421 GCStats(JSContext
*cx
, uintN argc
, jsval
*vp
)
1423 js_DumpGCStats(cx
->runtime
, stdout
);
1430 GCParameter(JSContext
*cx
, uintN argc
, jsval
*vp
)
1432 static const struct {
1436 {"maxBytes", JSGC_MAX_BYTES
},
1437 {"maxMallocBytes", JSGC_MAX_MALLOC_BYTES
},
1438 {"gcStackpoolLifespan", JSGC_STACKPOOL_LIFESPAN
},
1439 {"gcBytes", JSGC_BYTES
},
1440 {"gcNumber", JSGC_NUMBER
},
1441 {"gcTriggerFactor", JSGC_TRIGGER_FACTOR
},
1446 str
= JS_ValueToString(cx
, JSVAL_VOID
);
1449 str
= JS_ValueToString(cx
, vp
[2]);
1452 vp
[2] = STRING_TO_JSVAL(str
);
1455 JSFlatString
*flatStr
= JS_FlattenString(cx
, str
);
1459 size_t paramIndex
= 0;
1460 for (;; paramIndex
++) {
1461 if (paramIndex
== JS_ARRAY_LENGTH(paramMap
)) {
1463 "the first argument argument must be maxBytes, "
1464 "maxMallocBytes, gcStackpoolLifespan, gcBytes, "
1465 "gcNumber or gcTriggerFactor");
1468 if (JS_FlatStringEqualsAscii(flatStr
, paramMap
[paramIndex
].name
))
1471 JSGCParamKey param
= paramMap
[paramIndex
].param
;
1474 uint32 value
= JS_GetGCParameter(cx
->runtime
, param
);
1475 return JS_NewNumberValue(cx
, value
, &vp
[0]);
1478 if (param
== JSGC_NUMBER
||
1479 param
== JSGC_BYTES
) {
1480 JS_ReportError(cx
, "Attempt to change read-only parameter %s",
1481 paramMap
[paramIndex
].name
);
1486 if (!JS_ValueToECMAUint32(cx
, vp
[3], &value
)) {
1488 "the second argument must be convertable to uint32 "
1489 "with non-zero value");
1492 if (param
== JSGC_TRIGGER_FACTOR
&& value
< 100) {
1494 "the gcTriggerFactor value must be >= 100");
1497 JS_SetGCParameter(cx
->runtime
, param
, value
);
1504 GCZeal(JSContext
*cx
, uintN argc
, jsval
*vp
)
1508 if (!JS_ValueToECMAUint32(cx
, argc
== 0 ? JSVAL_VOID
: vp
[2], &zeal
))
1510 JS_SetGCZeal(cx
, (uint8
)zeal
);
1514 #endif /* JS_GC_ZEAL */
1516 typedef struct JSCountHeapNode JSCountHeapNode
;
1518 struct JSCountHeapNode
{
1521 JSCountHeapNode
*next
;
1524 typedef struct JSCountHeapTracer
{
1526 JSDHashTable visited
;
1528 JSCountHeapNode
*traceList
;
1529 JSCountHeapNode
*recycleList
;
1530 } JSCountHeapTracer
;
1533 CountHeapNotify(JSTracer
*trc
, void *thing
, uint32 kind
)
1535 JSCountHeapTracer
*countTracer
;
1536 JSDHashEntryStub
*entry
;
1537 JSCountHeapNode
*node
;
1539 JS_ASSERT(trc
->callback
== CountHeapNotify
);
1540 countTracer
= (JSCountHeapTracer
*)trc
;
1541 if (!countTracer
->ok
)
1544 entry
= (JSDHashEntryStub
*)
1545 JS_DHashTableOperate(&countTracer
->visited
, thing
, JS_DHASH_ADD
);
1547 JS_ReportOutOfMemory(trc
->context
);
1548 countTracer
->ok
= JS_FALSE
;
1555 node
= countTracer
->recycleList
;
1557 countTracer
->recycleList
= node
->next
;
1559 node
= (JSCountHeapNode
*) JS_malloc(trc
->context
, sizeof *node
);
1561 countTracer
->ok
= JS_FALSE
;
1565 node
->thing
= thing
;
1567 node
->next
= countTracer
->traceList
;
1568 countTracer
->traceList
= node
;
1572 CountHeap(JSContext
*cx
, uintN argc
, jsval
*vp
)
1575 int32 startTraceKind
;
1579 JSCountHeapTracer countTracer
;
1580 JSCountHeapNode
*node
;
1583 static const struct {
1586 } traceKindNames
[] = {
1588 { "object", JSTRACE_OBJECT
},
1589 { "string", JSTRACE_STRING
},
1590 #if JS_HAS_XML_SUPPORT
1591 { "xml", JSTRACE_XML
},
1598 v
= JS_ARGV(cx
, vp
)[0];
1599 if (JSVAL_IS_TRACEABLE(v
)) {
1600 startThing
= JSVAL_TO_TRACEABLE(v
);
1601 startTraceKind
= JSVAL_TRACE_KIND(v
);
1602 } else if (!JSVAL_IS_NULL(v
)) {
1604 "the first argument is not null or a heap-allocated "
1612 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[1]);
1615 JSFlatString
*flatStr
= JS_FlattenString(cx
, str
);
1619 if (JS_FlatStringEqualsAscii(flatStr
, traceKindNames
[i
].name
)) {
1620 traceKind
= traceKindNames
[i
].kind
;
1623 if (++i
== JS_ARRAY_LENGTH(traceKindNames
)) {
1624 JSAutoByteString
bytes(cx
, str
);
1626 JS_ReportError(cx
, "trace kind name '%s' is unknown", bytes
.ptr());
1632 JS_TRACER_INIT(&countTracer
.base
, cx
, CountHeapNotify
);
1633 if (!JS_DHashTableInit(&countTracer
.visited
, JS_DHashGetStubOps(),
1634 NULL
, sizeof(JSDHashEntryStub
),
1635 JS_DHASH_DEFAULT_CAPACITY(100))) {
1636 JS_ReportOutOfMemory(cx
);
1639 countTracer
.ok
= JS_TRUE
;
1640 countTracer
.traceList
= NULL
;
1641 countTracer
.recycleList
= NULL
;
1644 JS_TraceRuntime(&countTracer
.base
);
1646 JS_SET_TRACING_NAME(&countTracer
.base
, "root");
1647 JS_CallTracer(&countTracer
.base
, startThing
, startTraceKind
);
1651 while ((node
= countTracer
.traceList
) != NULL
) {
1652 if (traceKind
== -1 || node
->kind
== traceKind
)
1654 countTracer
.traceList
= node
->next
;
1655 node
->next
= countTracer
.recycleList
;
1656 countTracer
.recycleList
= node
;
1657 JS_TraceChildren(&countTracer
.base
, node
->thing
, node
->kind
);
1659 while ((node
= countTracer
.recycleList
) != NULL
) {
1660 countTracer
.recycleList
= node
->next
;
1663 JS_DHashTableFinish(&countTracer
.visited
);
1665 return countTracer
.ok
&& JS_NewNumberValue(cx
, (jsdouble
) counter
, vp
);
1668 static jsrefcount finalizeCount
= 0;
1671 finalize_counter_finalize(JSContext
*cx
, JSObject
*obj
)
1673 JS_ATOMIC_INCREMENT(&finalizeCount
);
1676 static JSClass FinalizeCounterClass
= {
1677 "FinalizeCounter", JSCLASS_IS_ANONYMOUS
,
1678 JS_PropertyStub
, /* addProperty */
1679 JS_PropertyStub
, /* delProperty */
1680 JS_PropertyStub
, /* getProperty */
1681 JS_StrictPropertyStub
, /* setProperty */
1685 finalize_counter_finalize
1689 MakeFinalizeObserver(JSContext
*cx
, uintN argc
, jsval
*vp
)
1691 JSObject
*obj
= JS_NewObjectWithGivenProto(cx
, &FinalizeCounterClass
, NULL
,
1692 JS_GetGlobalObject(cx
));
1695 *vp
= OBJECT_TO_JSVAL(obj
);
1700 FinalizeCount(JSContext
*cx
, uintN argc
, jsval
*vp
)
1702 *vp
= INT_TO_JSVAL(finalizeCount
);
1707 ValueToScript(JSContext
*cx
, jsval v
)
1709 JSScript
*script
= NULL
;
1712 if (!JSVAL_IS_PRIMITIVE(v
)) {
1713 JSObject
*obj
= JSVAL_TO_OBJECT(v
);
1714 JSClass
*clasp
= JS_GET_CLASS(cx
, obj
);
1716 if (clasp
== Jsvalify(&js_ScriptClass
)) {
1717 script
= (JSScript
*) JS_GetPrivate(cx
, obj
);
1718 } else if (clasp
== Jsvalify(&js_GeneratorClass
)) {
1719 JSGenerator
*gen
= (JSGenerator
*) JS_GetPrivate(cx
, obj
);
1720 fun
= gen
->floatingFrame()->fun();
1721 script
= FUN_SCRIPT(fun
);
1726 fun
= JS_ValueToFunction(cx
, v
);
1729 script
= FUN_SCRIPT(fun
);
1731 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1732 JSSMSG_SCRIPTS_ONLY
);
1740 SetDebug(JSContext
*cx
, uintN argc
, jsval
*vp
)
1742 jsval
*argv
= JS_ARGV(cx
, vp
);
1743 if (argc
== 0 || !JSVAL_IS_BOOLEAN(argv
[0])) {
1744 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1745 JSSMSG_NOT_ENOUGH_ARGS
, "setDebug");
1750 * Debug mode can only be set when there is no JS code executing on the
1751 * stack. Unfortunately, that currently means that this call will fail
1752 * unless debug mode is already set to what you're trying to set it to.
1753 * In the future, this restriction may be lifted.
1756 JSBool rv
= JS_SetDebugMode(cx
, JSVAL_TO_BOOLEAN(argv
[0]));
1757 JS_SET_RVAL(cx
, vp
, rv
? JSVAL_TRUE
: JSVAL_FALSE
);
1762 GetTrapArgs(JSContext
*cx
, uintN argc
, jsval
*argv
, JSScript
**scriptp
,
1769 *scriptp
= JS_GetScriptedCaller(cx
, NULL
)->script();
1774 if (!JSVAL_IS_PRIMITIVE(v
) &&
1775 (JS_GET_CLASS(cx
, JSVAL_TO_OBJECT(v
)) == Jsvalify(&js_FunctionClass
) ||
1776 JS_GET_CLASS(cx
, JSVAL_TO_OBJECT(v
)) == Jsvalify(&js_ScriptClass
))) {
1777 script
= ValueToScript(cx
, v
);
1783 if (argc
> intarg
) {
1784 if (!JS_ValueToInt32(cx
, argv
[intarg
], ip
))
1792 TrapHandler(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
,
1795 JSString
*str
= JSVAL_TO_STRING(closure
);
1796 JSStackFrame
*caller
= JS_GetScriptedCaller(cx
, NULL
);
1799 const jschar
*chars
= JS_GetStringCharsAndLength(cx
, str
, &length
);
1801 return JSTRAP_ERROR
;
1803 if (!JS_EvaluateUCInStackFrame(cx
, caller
, chars
, length
,
1804 caller
->script()->filename
,
1805 caller
->script()->lineno
,
1807 return JSTRAP_ERROR
;
1809 if (!JSVAL_IS_VOID(*rval
))
1810 return JSTRAP_RETURN
;
1811 return JSTRAP_CONTINUE
;
1815 Trap(JSContext
*cx
, uintN argc
, jsval
*vp
)
1821 jsval
*argv
= JS_ARGV(cx
, vp
);
1823 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_TRAP_USAGE
);
1827 str
= JS_ValueToString(cx
, argv
[argc
]);
1830 argv
[argc
] = STRING_TO_JSVAL(str
);
1831 if (!GetTrapArgs(cx
, argc
, argv
, &script
, &i
))
1833 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1834 return JS_SetTrap(cx
, script
, script
->code
+ i
, TrapHandler
, STRING_TO_JSVAL(str
));
1838 Untrap(JSContext
*cx
, uintN argc
, jsval
*vp
)
1843 if (!GetTrapArgs(cx
, argc
, JS_ARGV(cx
, vp
), &script
, &i
))
1845 JS_ClearTrap(cx
, script
, script
->code
+ i
, NULL
, NULL
);
1846 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1851 DebuggerAndThrowHandler(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
,
1854 return TrapHandler(cx
, script
, pc
, rval
, STRING_TO_JSVAL((JSString
*)closure
));
1858 SetDebuggerHandler(JSContext
*cx
, uintN argc
, jsval
*vp
)
1862 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1863 JSSMSG_NOT_ENOUGH_ARGS
, "setDebuggerHandler");
1867 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
1871 JS_SetDebuggerHandler(cx
->runtime
, DebuggerAndThrowHandler
, str
);
1872 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1877 SetThrowHook(JSContext
*cx
, uintN argc
, jsval
*vp
)
1881 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1882 JSSMSG_NOT_ENOUGH_ARGS
, "setThrowHook");
1886 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
1890 JS_SetThrowHook(cx
->runtime
, DebuggerAndThrowHandler
, str
);
1891 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
1896 LineToPC(JSContext
*cx
, uintN argc
, jsval
*vp
)
1904 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_LINE2PC_USAGE
);
1907 script
= JS_GetScriptedCaller(cx
, NULL
)->script();
1908 if (!GetTrapArgs(cx
, argc
, JS_ARGV(cx
, vp
), &script
, &i
))
1910 lineno
= (i
== 0) ? script
->lineno
: (uintN
)i
;
1911 pc
= JS_LineNumberToPC(cx
, script
, lineno
);
1914 *vp
= INT_TO_JSVAL(pc
- script
->code
);
1919 PCToLine(JSContext
*cx
, uintN argc
, jsval
*vp
)
1925 if (!GetTrapArgs(cx
, argc
, JS_ARGV(cx
, vp
), &script
, &i
))
1927 lineno
= JS_PCToLineNumber(cx
, script
, script
->code
+ i
);
1930 *vp
= INT_TO_JSVAL(lineno
);
1937 UpdateSwitchTableBounds(JSContext
*cx
, JSScript
*script
, uintN offset
,
1938 uintN
*start
, uintN
*end
)
1945 pc
= script
->code
+ offset
;
1946 op
= js_GetOpcode(cx
, script
, pc
);
1948 case JSOP_TABLESWITCHX
:
1949 jmplen
= JUMPX_OFFSET_LEN
;
1951 case JSOP_TABLESWITCH
:
1952 jmplen
= JUMP_OFFSET_LEN
;
1955 low
= GET_JUMP_OFFSET(pc
);
1956 pc
+= JUMP_OFFSET_LEN
;
1957 high
= GET_JUMP_OFFSET(pc
);
1958 pc
+= JUMP_OFFSET_LEN
;
1962 case JSOP_LOOKUPSWITCHX
:
1963 jmplen
= JUMPX_OFFSET_LEN
;
1965 case JSOP_LOOKUPSWITCH
:
1966 jmplen
= JUMP_OFFSET_LEN
;
1971 jmplen
+= JUMP_OFFSET_LEN
;
1975 /* [condswitch] switch does not have any jump or lookup tables. */
1976 JS_ASSERT(op
== JSOP_CONDSWITCH
);
1980 *start
= (uintN
)(pc
- script
->code
);
1981 *end
= *start
+ (uintN
)(n
* jmplen
);
1985 SrcNotes(JSContext
*cx
, JSScript
*script
)
1987 uintN offset
, delta
, caseOff
, switchTableStart
, switchTableEnd
;
1988 jssrcnote
*notes
, *sn
;
1995 fprintf(gOutFile
, "\nSource notes:\n");
1997 notes
= script
->notes();
1998 switchTableEnd
= switchTableStart
= 0;
1999 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
)) {
2000 delta
= SN_DELTA(sn
);
2002 type
= (JSSrcNoteType
) SN_TYPE(sn
);
2003 name
= js_SrcNoteSpec
[type
].name
;
2004 if (type
== SRC_LABEL
) {
2005 /* Check if the source note is for a switch case. */
2006 if (switchTableStart
<= offset
&& offset
< switchTableEnd
) {
2009 JS_ASSERT(js_GetOpcode(cx
, script
, script
->code
+ offset
) == JSOP_NOP
);
2012 fprintf(gOutFile
, "%3u: %5u [%4u] %-8s",
2013 (uintN
) (sn
- notes
), offset
, delta
, name
);
2016 fprintf(gOutFile
, " lineno %u", (uintN
) js_GetSrcNoteOffset(sn
, 0));
2019 fprintf(gOutFile
, " cond %u update %u tail %u",
2020 (uintN
) js_GetSrcNoteOffset(sn
, 0),
2021 (uintN
) js_GetSrcNoteOffset(sn
, 1),
2022 (uintN
) js_GetSrcNoteOffset(sn
, 2));
2025 fprintf(gOutFile
, " else %u elseif %u",
2026 (uintN
) js_GetSrcNoteOffset(sn
, 0),
2027 (uintN
) js_GetSrcNoteOffset(sn
, 1));
2035 fprintf(gOutFile
, " offset %u", (uintN
) js_GetSrcNoteOffset(sn
, 0));
2038 case SRC_LABELBRACE
:
2039 case SRC_BREAK2LABEL
:
2040 case SRC_CONT2LABEL
:
2041 index
= js_GetSrcNoteOffset(sn
, 0);
2042 JS_GET_SCRIPT_ATOM(script
, NULL
, index
, atom
);
2043 str
= ATOM_TO_STRING(atom
);
2044 fprintf(gOutFile
, " atom %u (", index
);
2045 JS_FileEscapedString(gOutFile
, str
, 0);
2046 putc(')', gOutFile
);
2049 index
= js_GetSrcNoteOffset(sn
, 0);
2050 JSObject
*obj
= script
->getObject(index
);
2051 JSFunction
*fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
2052 str
= JS_DecompileFunction(cx
, fun
, JS_DONT_PRETTY_PRINT
);
2053 JSAutoByteString bytes
;
2054 if (!str
|| !bytes
.encode(cx
, str
))
2055 ReportException(cx
);
2056 fprintf(gOutFile
, " function %u (%s)", index
, !!bytes
? bytes
.ptr() : "N/A");
2060 fprintf(gOutFile
, " length %u", (uintN
) js_GetSrcNoteOffset(sn
, 0));
2061 caseOff
= (uintN
) js_GetSrcNoteOffset(sn
, 1);
2063 fprintf(gOutFile
, " first case offset %u", caseOff
);
2064 UpdateSwitchTableBounds(cx
, script
, offset
,
2065 &switchTableStart
, &switchTableEnd
);
2068 delta
= (uintN
) js_GetSrcNoteOffset(sn
, 0);
2070 if (script
->main
[offset
] == JSOP_LEAVEBLOCK
)
2071 fprintf(gOutFile
, " stack depth %u", delta
);
2073 fprintf(gOutFile
, " guard delta %u", delta
);
2078 fputc('\n', gOutFile
);
2083 Notes(JSContext
*cx
, uintN argc
, jsval
*vp
)
2088 jsval
*argv
= JS_ARGV(cx
, vp
);
2089 for (i
= 0; i
< argc
; i
++) {
2090 script
= ValueToScript(cx
, argv
[i
]);
2094 SrcNotes(cx
, script
);
2096 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2100 JS_STATIC_ASSERT(JSTRY_CATCH
== 0);
2101 JS_STATIC_ASSERT(JSTRY_FINALLY
== 1);
2102 JS_STATIC_ASSERT(JSTRY_ITER
== 2);
2104 static const char* const TryNoteNames
[] = { "catch", "finally", "iter" };
2107 TryNotes(JSContext
*cx
, JSScript
*script
)
2109 JSTryNote
*tn
, *tnlimit
;
2111 if (!JSScript::isValidOffset(script
->trynotesOffset
))
2114 tn
= script
->trynotes()->vector
;
2115 tnlimit
= tn
+ script
->trynotes()->length
;
2116 fprintf(gOutFile
, "\nException table:\n"
2117 "kind stack start end\n");
2119 JS_ASSERT(tn
->kind
< JS_ARRAY_LENGTH(TryNoteNames
));
2120 fprintf(gOutFile
, " %-7s %6u %8u %8u\n",
2121 TryNoteNames
[tn
->kind
], tn
->stackDepth
,
2122 tn
->start
, tn
->start
+ tn
->length
);
2123 } while (++tn
!= tnlimit
);
2128 DisassembleValue(JSContext
*cx
, jsval v
, bool lines
, bool recursive
)
2130 JSScript
*script
= ValueToScript(cx
, v
);
2133 if (VALUE_IS_FUNCTION(cx
, v
)) {
2134 JSFunction
*fun
= JS_ValueToFunction(cx
, v
);
2135 if (fun
&& (fun
->flags
& ~7U)) {
2136 uint16 flags
= fun
->flags
;
2137 fputs("flags:", stdout
);
2139 #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
2142 SHOW_FLAG(HEAVYWEIGHT
);
2143 SHOW_FLAG(EXPR_CLOSURE
);
2148 if (FUN_INTERPRETED(fun
)) {
2149 if (FUN_NULL_CLOSURE(fun
))
2150 fputs(" NULL_CLOSURE", stdout
);
2151 else if (FUN_FLAT_CLOSURE(fun
))
2152 fputs(" FLAT_CLOSURE", stdout
);
2154 JSScript
*script
= fun
->script();
2155 if (script
->bindings
.hasUpvars()) {
2156 fputs("\nupvars: {\n", stdout
);
2158 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
2159 jsuword
*localNames
= script
->bindings
.getLocalNameArray(cx
, &cx
->tempPool
);
2163 JSUpvarArray
*uva
= script
->upvars();
2164 uintN upvar_base
= script
->bindings
.countArgsAndVars();
2166 for (uint32 i
= 0, n
= uva
->length
; i
< n
; i
++) {
2167 JSAtom
*atom
= JS_LOCAL_NAME_TO_ATOM(localNames
[upvar_base
+ i
]);
2168 UpvarCookie cookie
= uva
->vector
[i
];
2169 JSAutoByteString printable
;
2170 if (js_AtomToPrintableString(cx
, atom
, &printable
)) {
2171 printf(" %s: {skip:%u, slot:%u},\n",
2172 printable
.ptr(), cookie
.level(), cookie
.slot());
2176 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
2184 if (!js_Disassemble(cx
, script
, lines
, stdout
))
2186 SrcNotes(cx
, script
);
2187 TryNotes(cx
, script
);
2189 if (recursive
&& JSScript::isValidOffset(script
->objectsOffset
)) {
2190 JSObjectArray
*objects
= script
->objects();
2191 for (uintN i
= 0; i
!= objects
->length
; ++i
) {
2192 JSObject
*obj
= objects
->vector
[i
];
2193 if (obj
->isFunction()) {
2195 if (!DisassembleValue(cx
, OBJECT_TO_JSVAL(obj
),
2196 lines
, recursive
)) {
2206 Disassemble(JSContext
*cx
, uintN argc
, jsval
*vp
)
2208 jsval
*argv
= JS_ARGV(cx
, vp
);
2210 /* Read options off early arguments */
2211 bool lines
= false, recursive
= false;
2212 while (argc
> 0 && JSVAL_IS_STRING(argv
[0])) {
2213 JSString
*str
= JSVAL_TO_STRING(argv
[0]);
2214 JSFlatString
*flatStr
= JS_FlattenString(cx
, str
);
2217 lines
|= !!JS_FlatStringEqualsAscii(flatStr
, "-l");
2218 recursive
|= !!JS_FlatStringEqualsAscii(flatStr
, "-r");
2219 if (!lines
&& !recursive
)
2225 /* Without arguments, disassemble the current script. */
2226 if (JSStackFrame
*frame
= JS_GetScriptedCaller(cx
, NULL
)) {
2227 JSScript
*script
= JS_GetFrameScript(cx
, frame
);
2228 if (!js_Disassemble(cx
, script
, lines
, stdout
))
2230 SrcNotes(cx
, script
);
2231 TryNotes(cx
, script
);
2234 for (uintN i
= 0; i
< argc
; i
++) {
2235 if (!DisassembleValue(cx
, argv
[i
], lines
, recursive
))
2240 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2245 DisassFile(JSContext
*cx
, uintN argc
, jsval
*vp
)
2247 jsval
*argv
= JS_ARGV(cx
, vp
);
2250 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2254 /* Support extra options at the start, just like Dissassemble. */
2260 JSObject
*thisobj
= JS_THIS_OBJECT(cx
, vp
);
2264 JSString
*str
= JS_ValueToString(cx
, argv
[0]);
2267 JSAutoByteString
filename(cx
, str
);
2271 uint32 oldopts
= JS_GetOptions(cx
);
2272 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
| JSOPTION_NO_SCRIPT_RVAL
);
2273 JSScript
*script
= JS_CompileFile(cx
, thisobj
, filename
.ptr());
2274 JS_SetOptions(cx
, oldopts
);
2278 JSObject
*obj
= JS_NewScriptObject(cx
, script
);
2282 argv
[0] = OBJECT_TO_JSVAL(obj
); /* I like to root it, root it. */
2283 JSBool ok
= Disassemble(cx
, _argc
, vp
); /* gross, but works! */
2284 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2289 DisassWithSrc(JSContext
*cx
, uintN argc
, jsval
*vp
)
2291 #define LINE_BUF_LEN 512
2292 uintN i
, len
, line1
, line2
, bupline
;
2295 char linebuf
[LINE_BUF_LEN
];
2296 jsbytecode
*pc
, *end
;
2298 static char sep
[] = ";-------------------------";
2301 jsval
*argv
= JS_ARGV(cx
, vp
);
2302 for (i
= 0; ok
&& i
< argc
; i
++) {
2303 script
= ValueToScript(cx
, argv
[i
]);
2307 if (!script
->filename
) {
2308 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
2309 JSSMSG_FILE_SCRIPTS_ONLY
);
2313 file
= fopen(script
->filename
, "r");
2315 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
2316 JSSMSG_CANT_OPEN
, script
->filename
,
2322 end
= pc
+ script
->length
;
2324 /* burn the leading lines */
2325 line2
= JS_PCToLineNumber(cx
, script
, pc
);
2326 for (line1
= 0; line1
< line2
- 1; line1
++) {
2327 char *tmp
= fgets(linebuf
, LINE_BUF_LEN
, file
);
2329 JS_ReportError(cx
, "failed to read %s fully",
2338 line2
= JS_PCToLineNumber(cx
, script
, pc
);
2340 if (line2
< line1
) {
2341 if (bupline
!= line2
) {
2343 fprintf(gOutFile
, "%s %3u: BACKUP\n", sep
, line2
);
2346 if (bupline
&& line1
== line2
)
2347 fprintf(gOutFile
, "%s %3u: RESTORE\n", sep
, line2
);
2349 while (line1
< line2
) {
2350 if (!fgets(linebuf
, LINE_BUF_LEN
, file
)) {
2351 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
2352 JSSMSG_UNEXPECTED_EOF
,
2358 fprintf(gOutFile
, "%s %3u: %s", sep
, line1
, linebuf
);
2362 len
= js_Disassemble1(cx
, script
, pc
,
2375 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2381 Tracing(JSContext
*cx
, uintN argc
, jsval
*vp
)
2386 *vp
= BOOLEAN_TO_JSVAL(cx
->logfp
!= 0);
2390 jsval
*argv
= JS_ARGV(cx
, vp
);
2391 switch (JS_TypeOfValue(cx
, argv
[0])) {
2393 case JSTYPE_BOOLEAN
: {
2395 JS_ValueToBoolean(cx
, argv
[0], &bval
);
2396 file
= bval
? stderr
: NULL
;
2399 case JSTYPE_STRING
: {
2400 JSAutoByteString
name(cx
, JSVAL_TO_STRING(argv
[0]));
2403 file
= fopen(name
.ptr(), "w");
2405 JS_ReportError(cx
, "tracing: couldn't open output file %s: %s",
2406 name
.ptr(), strerror(errno
));
2414 if (cx
->logfp
&& cx
->logfp
!= stderr
)
2415 fclose((FILE *)cx
->logfp
);
2417 cx
->logPrevPc
= NULL
;
2418 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2422 JSString
*str
= JS_ValueToString(cx
, argv
[0]);
2425 JSAutoByteString
bytes(cx
, str
);
2428 JS_ReportError(cx
, "tracing: illegal argument %s", bytes
.ptr());
2433 DumpScope(JSContext
*cx
, JSObject
*obj
, FILE *fp
)
2436 for (JSScopeProperty
*sprop
= NULL
; JS_PropertyIterator(obj
, &sprop
);) {
2437 fprintf(fp
, "%3u %p ", i
++, (void *) sprop
);
2438 ((Shape
*) sprop
)->dump(cx
, fp
);
2443 DumpStats(JSContext
*cx
, uintN argc
, jsval
*vp
)
2452 jsval
*argv
= JS_ARGV(cx
, vp
);
2453 for (i
= 0; i
< argc
; i
++) {
2454 str
= JS_ValueToString(cx
, argv
[i
]);
2457 argv
[i
] = STRING_TO_JSVAL(str
);
2458 JSFlatString
*flatStr
= JS_FlattenString(cx
, str
);
2461 if (JS_FlatStringEqualsAscii(flatStr
, "arena")) {
2462 #ifdef JS_ARENAMETER
2463 JS_DumpArenaStats(stdout
);
2465 } else if (JS_FlatStringEqualsAscii(flatStr
, "atom")) {
2466 js_DumpAtoms(cx
, gOutFile
);
2467 } else if (JS_FlatStringEqualsAscii(flatStr
, "global")) {
2468 DumpScope(cx
, cx
->globalObject
, stdout
);
2470 if (!JS_ValueToId(cx
, STRING_TO_JSVAL(str
), &id
))
2473 if (!js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
))
2476 if (!obj
->getProperty(cx
, id
, &value
))
2479 if (!prop
|| !value
.isObjectOrNull()) {
2480 fputs("js: invalid stats argument ", gErrFile
);
2481 JS_FileEscapedString(gErrFile
, str
, 0);
2482 putc('\n', gErrFile
);
2485 obj
= value
.toObjectOrNull();
2487 DumpScope(cx
, obj
, stdout
);
2490 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2495 DumpHeap(JSContext
*cx
, uintN argc
, jsval
*vp
)
2499 uint32 startTraceKind
;
2500 const char *badTraceArg
;
2503 void *thingToIgnore
;
2507 const char *fileName
= NULL
;
2508 JSAutoByteString fileNameBytes
;
2510 v
= JS_ARGV(cx
, vp
)[0];
2511 if (!JSVAL_IS_NULL(v
)) {
2514 str
= JS_ValueToString(cx
, v
);
2517 JS_ARGV(cx
, vp
)[0] = STRING_TO_JSVAL(str
);
2518 if (!fileNameBytes
.encode(cx
, str
))
2520 fileName
= fileNameBytes
.ptr();
2527 v
= JS_ARGV(cx
, vp
)[1];
2528 if (JSVAL_IS_TRACEABLE(v
)) {
2529 startThing
= JSVAL_TO_TRACEABLE(v
);
2530 startTraceKind
= JSVAL_TRACE_KIND(v
);
2531 } else if (!JSVAL_IS_NULL(v
)) {
2532 badTraceArg
= "start";
2533 goto not_traceable_arg
;
2539 v
= JS_ARGV(cx
, vp
)[2];
2540 if (JSVAL_IS_TRACEABLE(v
)) {
2541 thingToFind
= JSVAL_TO_TRACEABLE(v
);
2542 } else if (!JSVAL_IS_NULL(v
)) {
2543 badTraceArg
= "toFind";
2544 goto not_traceable_arg
;
2548 maxDepth
= (size_t)-1;
2550 v
= JS_ARGV(cx
, vp
)[3];
2551 if (!JSVAL_IS_NULL(v
)) {
2554 if (!JS_ValueToECMAUint32(cx
, v
, &depth
))
2560 thingToIgnore
= NULL
;
2562 v
= JS_ARGV(cx
, vp
)[4];
2563 if (JSVAL_IS_TRACEABLE(v
)) {
2564 thingToIgnore
= JSVAL_TO_TRACEABLE(v
);
2565 } else if (!JSVAL_IS_NULL(v
)) {
2566 badTraceArg
= "toIgnore";
2567 goto not_traceable_arg
;
2574 dumpFile
= fopen(fileName
, "w");
2576 JS_ReportError(cx
, "can't open %s: %s", fileName
, strerror(errno
));
2581 ok
= JS_DumpHeap(cx
, dumpFile
, startThing
, startTraceKind
, thingToFind
,
2582 maxDepth
, thingToIgnore
);
2583 if (dumpFile
!= stdout
)
2588 JS_ReportError(cx
, "argument '%s' is not null or a heap-allocated thing",
2594 DumpObject(JSContext
*cx
, uintN argc
, jsval
*vp
)
2596 JSObject
*arg0
= NULL
;
2597 if (!JS_ConvertArguments(cx
, argc
, JS_ARGV(cx
, vp
), "o", &arg0
))
2600 js_DumpObject(arg0
);
2602 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2612 EscapeWideString(jschar
*w
)
2614 static char enuf
[80];
2615 static char hex
[] = "0123456789abcdef";
2622 for (i
= j
= 0; i
< sizeof enuf
- 1; i
++, j
++) {
2626 b
= (unsigned char)(u
>> 8);
2627 c
= (unsigned char)(u
);
2629 if (i
>= sizeof enuf
- 6)
2633 enuf
[i
++] = hex
[b
>> 4];
2634 enuf
[i
++] = hex
[b
& 15];
2635 enuf
[i
++] = hex
[c
>> 4];
2636 enuf
[i
] = hex
[c
& 15];
2637 } else if (!isprint(c
)) {
2638 if (i
>= sizeof enuf
- 4)
2642 enuf
[i
++] = hex
[c
>> 4];
2643 enuf
[i
] = hex
[c
& 15];
2655 ZZ_formatter(JSContext
*cx
, const char *format
, JSBool fromJS
, jsval
**vpp
,
2662 printf("entering ZZ_formatter");
2666 if (!JS_ValueToNumber(cx
, vp
[0], &re
))
2668 if (!JS_ValueToNumber(cx
, vp
[1], &im
))
2670 *va_arg(ap
, jsdouble
*) = re
;
2671 *va_arg(ap
, jsdouble
*) = im
;
2673 re
= va_arg(ap
, jsdouble
);
2674 im
= va_arg(ap
, jsdouble
);
2675 if (!JS_NewNumberValue(cx
, re
, &vp
[0]))
2677 if (!JS_NewNumberValue(cx
, im
, &vp
[1]))
2682 printf("leaving ZZ_formatter");
2687 ConvertArgs(JSContext
*cx
, uintN argc
, jsval
*vp
)
2689 JSBool b
= JS_FALSE
;
2693 jsdouble d
= 0, I
= 0, re
= 0, im
= 0;
2694 JSString
*str
= NULL
;
2696 JSObject
*obj2
= NULL
;
2697 JSFunction
*fun
= NULL
;
2698 jsval v
= JSVAL_VOID
;
2701 if (!JS_AddArgumentFormatter(cx
, "ZZ", ZZ_formatter
))
2703 ok
= JS_ConvertArguments(cx
, argc
, JS_ARGV(cx
, vp
), "b/ciujdISWofvZZ*",
2704 &b
, &c
, &i
, &u
, &j
, &d
, &I
, &str
, &w
, &obj2
,
2705 &fun
, &v
, &re
, &im
);
2706 JS_RemoveArgumentFormatter(cx
, "ZZ");
2710 "b %u, c %x (%c), i %ld, u %lu, j %ld\n",
2711 b
, c
, (char)c
, i
, u
, j
);
2712 ToString
obj2string(cx
, obj2
);
2713 ToString
valueString(cx
, v
);
2714 JSAutoByteString strBytes
;
2716 strBytes
.encode(cx
, str
);
2717 JSString
*tmpstr
= JS_DecompileFunction(cx
, fun
, 4);
2718 JSAutoByteString func
;
2719 if (!tmpstr
|| !func
.encode(cx
, tmpstr
));
2720 ReportException(cx
);
2722 "d %g, I %g, S %s, W %s, obj %s, fun %s\n"
2723 "v %s, re %g, im %g\n",
2724 d
, I
, !!strBytes
? strBytes
.ptr() : "", EscapeWideString(w
),
2725 obj2string
.getBytes(),
2726 fun
? (!!func
? func
.ptr() : "error decompiling fun") : "",
2727 valueString
.getBytes(), re
, im
);
2728 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2734 BuildDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
2736 char version
[20] = "\n";
2737 #if JS_VERSION < 150
2738 sprintf(version
, " for version %d\n", JS_VERSION
);
2740 fprintf(gOutFile
, "built on %s at %s%s", __DATE__
, __TIME__
, version
);
2746 Clear(JSContext
*cx
, uintN argc
, jsval
*vp
)
2749 if (argc
!= 0 && !JS_ValueToObject(cx
, JS_ARGV(cx
, vp
)[0], &obj
))
2751 JS_ClearScope(cx
, obj
);
2752 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2757 Intern(JSContext
*cx
, uintN argc
, jsval
*vp
)
2759 JSString
*str
= JS_ValueToString(cx
, argc
== 0 ? JSVAL_VOID
: vp
[2]);
2764 const jschar
*chars
= JS_GetStringCharsAndLength(cx
, str
, &length
);
2768 if (!JS_InternUCStringN(cx
, chars
, length
))
2771 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2776 Clone(JSContext
*cx
, uintN argc
, jsval
*vp
)
2778 JSObject
*funobj
, *parent
, *clone
;
2783 jsval
*argv
= JS_ARGV(cx
, vp
);
2784 if (VALUE_IS_FUNCTION(cx
, argv
[0])) {
2785 funobj
= JSVAL_TO_OBJECT(argv
[0]);
2787 JSFunction
*fun
= JS_ValueToFunction(cx
, argv
[0]);
2790 funobj
= JS_GetFunctionObject(fun
);
2793 if (!JS_ValueToObject(cx
, argv
[1], &parent
))
2796 parent
= JS_GetParent(cx
, funobj
);
2798 clone
= JS_CloneFunctionObject(cx
, funobj
, parent
);
2801 *vp
= OBJECT_TO_JSVAL(clone
);
2806 GetPDA(JSContext
*cx
, uintN argc
, jsval
*vp
)
2808 JSObject
*vobj
, *aobj
, *pdobj
;
2810 JSPropertyDescArray pda
;
2815 if (!JS_ValueToObject(cx
, argc
== 0 ? JSVAL_VOID
: vp
[2], &vobj
))
2822 aobj
= JS_NewArrayObject(cx
, 0, NULL
);
2825 *vp
= OBJECT_TO_JSVAL(aobj
);
2827 ok
= JS_GetPropertyDescArray(cx
, vobj
, &pda
);
2831 for (i
= 0; i
< pda
.length
; i
++, pd
++) {
2832 pdobj
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
2838 /* Protect pdobj from GC by setting it as an element of aobj now */
2839 v
= OBJECT_TO_JSVAL(pdobj
);
2840 ok
= JS_SetElement(cx
, aobj
, i
, &v
);
2844 ok
= JS_SetProperty(cx
, pdobj
, "id", &pd
->id
) &&
2845 JS_SetProperty(cx
, pdobj
, "value", &pd
->value
) &&
2846 (v
= INT_TO_JSVAL(pd
->flags
),
2847 JS_SetProperty(cx
, pdobj
, "flags", &v
)) &&
2848 (v
= INT_TO_JSVAL(pd
->slot
),
2849 JS_SetProperty(cx
, pdobj
, "slot", &v
)) &&
2850 JS_SetProperty(cx
, pdobj
, "alias", &pd
->alias
);
2854 JS_PutPropertyDescArray(cx
, &pda
);
2859 GetSLX(JSContext
*cx
, uintN argc
, jsval
*vp
)
2863 script
= ValueToScript(cx
, argc
== 0 ? JSVAL_VOID
: vp
[2]);
2866 *vp
= INT_TO_JSVAL(js_GetScriptLineExtent(script
));
2871 ToInt32(JSContext
*cx
, uintN argc
, jsval
*vp
)
2875 if (!JS_ValueToInt32(cx
, argc
== 0 ? JSVAL_VOID
: vp
[2], &i
))
2877 return JS_NewNumberValue(cx
, i
, vp
);
2881 StringsAreUTF8(JSContext
*cx
, uintN argc
, jsval
*vp
)
2883 *vp
= JS_CStringsAreUTF8() ? JSVAL_TRUE
: JSVAL_FALSE
;
2888 StackQuota(JSContext
*cx
, uintN argc
, jsval
*vp
)
2893 return JS_NewNumberValue(cx
, (double) gScriptStackQuota
, vp
);
2894 if (!JS_ValueToECMAUint32(cx
, JS_ARGV(cx
, vp
)[0], &n
))
2896 gScriptStackQuota
= n
;
2897 JS_SetScriptStackQuota(cx
, gScriptStackQuota
);
2898 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2902 static const char* badUTF8
= "...\xC0...";
2903 static const char* bigUTF8
= "...\xFB\xBF\xBF\xBF\xBF...";
2904 static const jschar badSurrogate
[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 };
2907 TestUTF8(JSContext
*cx
, uintN argc
, jsval
*vp
)
2911 size_t charsLength
= 5;
2913 size_t bytesLength
= 20;
2914 if (argc
&& !JS_ValueToInt32(cx
, *JS_ARGV(cx
, vp
), &mode
))
2917 /* The following throw errors if compiled with UTF-8. */
2919 /* mode 1: malformed UTF-8 string. */
2921 JS_NewStringCopyZ(cx
, badUTF8
);
2923 /* mode 2: big UTF-8 character. */
2925 JS_NewStringCopyZ(cx
, bigUTF8
);
2927 /* mode 3: bad surrogate character. */
2929 JS_EncodeCharacters(cx
, badSurrogate
, 6, bytes
, &bytesLength
);
2931 /* mode 4: use a too small buffer. */
2933 JS_DecodeBytes(cx
, "1234567890", 10, chars
, &charsLength
);
2936 JS_ReportError(cx
, "invalid mode parameter");
2939 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2940 return !JS_IsExceptionPending (cx
);
2944 ThrowError(JSContext
*cx
, uintN argc
, jsval
*vp
)
2946 JS_ReportError(cx
, "This is an error");
2950 #define LAZY_STANDARD_CLASSES
2952 /* A class for easily testing the inner/outer object callbacks. */
2953 typedef struct ComplexObject
{
2961 split_create_outer(JSContext
*cx
);
2964 split_create_inner(JSContext
*cx
, JSObject
*outer
);
2966 static ComplexObject
*
2967 split_get_private(JSContext
*cx
, JSObject
*obj
);
2970 split_addProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
2974 cpx
= split_get_private(cx
, obj
);
2977 if (!cpx
->isInner
&& cpx
->inner
) {
2978 /* Make sure to define this property on the inner object. */
2979 return JS_DefinePropertyById(cx
, cpx
->inner
, id
, *vp
, NULL
, NULL
, JSPROP_ENUMERATE
);
2985 split_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
2989 cpx
= split_get_private(cx
, obj
);
2993 if (JSID_IS_ATOM(id
) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id
), "isInner")) {
2994 *vp
= BOOLEAN_TO_JSVAL(cpx
->isInner
);
2998 if (!cpx
->isInner
&& cpx
->inner
) {
2999 if (JSID_IS_ATOM(id
)) {
3000 JSString
*str
= JSID_TO_STRING(id
);
3003 const jschar
*chars
= JS_GetStringCharsAndLength(cx
, str
, &length
);
3007 return JS_GetUCProperty(cx
, cpx
->inner
, chars
, length
, vp
);
3009 if (JSID_IS_INT(id
))
3010 return JS_GetElement(cx
, cpx
->inner
, JSID_TO_INT(id
), vp
);
3018 split_setProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, jsval
*vp
)
3022 cpx
= split_get_private(cx
, obj
);
3025 if (!cpx
->isInner
&& cpx
->inner
) {
3026 if (JSID_IS_ATOM(id
)) {
3027 JSString
*str
= JSID_TO_STRING(id
);
3030 const jschar
*chars
= JS_GetStringCharsAndLength(cx
, str
, &length
);
3034 return JS_SetUCProperty(cx
, cpx
->inner
, chars
, length
, vp
);
3036 if (JSID_IS_INT(id
))
3037 return JS_SetElement(cx
, cpx
->inner
, JSID_TO_INT(id
), vp
);
3045 split_delProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
3050 cpx
= split_get_private(cx
, obj
);
3053 if (!cpx
->isInner
&& cpx
->inner
) {
3054 /* Make sure to define this property on the inner object. */
3055 if (!JS_ValueToId(cx
, *vp
, &asId
))
3057 return cpx
->inner
->deleteProperty(cx
, asId
, Valueify(vp
), true);
3063 split_enumerate(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
3064 jsval
*statep
, jsid
*idp
)
3070 case JSENUMERATE_INIT
:
3071 case JSENUMERATE_INIT_ALL
:
3072 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
3074 if (!cpx
->isInner
&& cpx
->inner
)
3077 iterator
= JS_NewPropertyIterator(cx
, obj
);
3081 *statep
= OBJECT_TO_JSVAL(iterator
);
3083 *idp
= INT_TO_JSID(0);
3086 case JSENUMERATE_NEXT
:
3087 iterator
= (JSObject
*)JSVAL_TO_OBJECT(*statep
);
3088 if (!JS_NextProperty(cx
, iterator
, idp
))
3091 if (!JSID_IS_VOID(*idp
))
3095 case JSENUMERATE_DESTROY
:
3096 /* Let GC at our iterator object. */
3097 *statep
= JSVAL_NULL
;
3105 ResolveClass(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool
*resolved
)
3107 if (!JS_ResolveStandardClass(cx
, obj
, id
, resolved
))
3111 if (JSID_IS_ATOM(id
, CLASS_ATOM(cx
, Reflect
))) {
3112 if (!js_InitReflectClass(cx
, obj
))
3114 *resolved
= JS_TRUE
;
3122 split_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
, JSObject
**objp
)
3126 if (JSID_IS_ATOM(id
) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id
), "isInner")) {
3128 return JS_DefinePropertyById(cx
, obj
, id
, JSVAL_VOID
, NULL
, NULL
, JSPROP_SHARED
);
3131 cpx
= split_get_private(cx
, obj
);
3134 if (!cpx
->isInner
&& cpx
->inner
) {
3136 return cpx
->inner
->lookupProperty(cx
, id
, objp
, &prop
);
3139 #ifdef LAZY_STANDARD_CLASSES
3140 if (!(flags
& JSRESOLVE_ASSIGNING
)) {
3143 if (!ResolveClass(cx
, obj
, id
, &resolved
))
3153 /* XXX For additional realism, let's resolve some random property here. */
3158 split_finalize(JSContext
*cx
, JSObject
*obj
)
3160 JS_free(cx
, JS_GetPrivate(cx
, obj
));
3164 split_mark(JSContext
*cx
, JSObject
*obj
, void *arg
)
3168 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
3170 if (!cpx
->isInner
&& cpx
->inner
) {
3171 /* Mark the inner object. */
3172 JS_MarkGCThing(cx
, OBJECT_TO_JSVAL(cpx
->inner
), "ComplexObject.inner", arg
);
3175 if (cpx
->isInner
&& cpx
->outer
) {
3176 /* Mark the inner object. */
3177 JS_MarkGCThing(cx
, OBJECT_TO_JSVAL(cpx
->outer
), "ComplexObject.outer", arg
);
3184 split_outerObject(JSContext
*cx
, JSObject
*obj
)
3188 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
3189 return cpx
->isInner
? cpx
->outer
: obj
;
3193 split_thisObject(JSContext
*cx
, JSObject
*obj
)
3195 OBJ_TO_OUTER_OBJECT(cx
, obj
);
3203 split_equality(JSContext
*cx
, JSObject
*obj
, const jsval
*v
, JSBool
*bp
);
3206 split_innerObject(JSContext
*cx
, JSObject
*obj
)
3210 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
3212 JS_ASSERT(!cpx
->isInner
);
3215 return !cpx
->isInner
? cpx
->inner
: obj
;
3218 static Class split_global_class
= {
3220 JSCLASS_NEW_RESOLVE
| JSCLASS_NEW_ENUMERATE
| JSCLASS_HAS_PRIVATE
| JSCLASS_GLOBAL_FLAGS
,
3221 Valueify(split_addProperty
),
3222 Valueify(split_delProperty
),
3223 Valueify(split_getProperty
),
3224 Valueify(split_setProperty
),
3225 (JSEnumerateOp
)split_enumerate
,
3226 (JSResolveOp
)split_resolve
,
3229 NULL
, /* reserved0 */
3230 NULL
, /* checkAccess */
3232 NULL
, /* construct */
3233 NULL
, /* xdrObject */
3234 NULL
, /* hasInstance */
3237 Valueify(split_equality
),
3240 NULL
, /* iteratorObject */
3241 NULL
, /* wrappedObject */
3244 NULL
, /* lookupProperty */
3245 NULL
, /* defineProperty */
3246 NULL
, /* getProperty */
3247 NULL
, /* setProperty */
3248 NULL
, /* getAttributes */
3249 NULL
, /* setAttributes */
3250 NULL
, /* deleteProperty */
3251 NULL
, /* enumerate */
3261 split_equality(JSContext
*cx
, JSObject
*obj
, const jsval
*v
, JSBool
*bp
)
3264 if (JSVAL_IS_PRIMITIVE(*v
))
3267 JSObject
*obj2
= JSVAL_TO_OBJECT(*v
);
3268 if (obj2
->getClass() != &split_global_class
)
3271 ComplexObject
*cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj2
);
3272 JS_ASSERT(!cpx
->isInner
);
3274 ComplexObject
*ourCpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
3275 JS_ASSERT(!ourCpx
->isInner
);
3277 *bp
= (cpx
== ourCpx
);
3282 split_create_outer(JSContext
*cx
)
3287 cpx
= (ComplexObject
*) JS_malloc(cx
, sizeof *obj
);
3290 cpx
->isInner
= JS_FALSE
;
3291 cpx
->frozen
= JS_TRUE
;
3295 obj
= JS_NewGlobalObject(cx
, Jsvalify(&split_global_class
));
3301 if (!JS_SetPrivate(cx
, obj
, cpx
)) {
3310 split_create_inner(JSContext
*cx
, JSObject
*outer
)
3312 ComplexObject
*cpx
, *outercpx
;
3315 JS_ASSERT(outer
->getClass() == &split_global_class
);
3317 cpx
= (ComplexObject
*) JS_malloc(cx
, sizeof *cpx
);
3320 cpx
->isInner
= JS_TRUE
;
3321 cpx
->frozen
= JS_FALSE
;
3325 obj
= JS_NewGlobalObject(cx
, Jsvalify(&split_global_class
));
3326 if (!obj
|| !JS_SetPrivate(cx
, obj
, cpx
)) {
3331 outercpx
= (ComplexObject
*) JS_GetPrivate(cx
, outer
);
3332 outercpx
->inner
= obj
;
3333 outercpx
->frozen
= JS_FALSE
;
3338 static ComplexObject
*
3339 split_get_private(JSContext
*cx
, JSObject
*obj
)
3342 if (obj
->getClass() == &split_global_class
)
3343 return (ComplexObject
*) JS_GetPrivate(cx
, obj
);
3344 obj
= JS_GetParent(cx
, obj
);
3351 sandbox_enumerate(JSContext
*cx
, JSObject
*obj
)
3356 if (!JS_GetProperty(cx
, obj
, "lazy", &v
))
3359 JS_ValueToBoolean(cx
, v
, &b
);
3360 return !b
|| JS_EnumerateStandardClasses(cx
, obj
);
3364 sandbox_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
3370 if (!JS_GetProperty(cx
, obj
, "lazy", &v
))
3373 JS_ValueToBoolean(cx
, v
, &b
);
3374 if (b
&& (flags
& JSRESOLVE_ASSIGNING
) == 0) {
3375 if (!ResolveClass(cx
, obj
, id
, &resolved
))
3386 static JSClass sandbox_class
= {
3388 JSCLASS_NEW_RESOLVE
| JSCLASS_GLOBAL_FLAGS
,
3389 JS_PropertyStub
, JS_PropertyStub
,
3390 JS_PropertyStub
, JS_StrictPropertyStub
,
3391 sandbox_enumerate
, (JSResolveOp
)sandbox_resolve
,
3392 JS_ConvertStub
, NULL
,
3393 JSCLASS_NO_OPTIONAL_MEMBERS
3397 NewSandbox(JSContext
*cx
, bool lazy
, bool split
)
3399 JSObject
*obj
= JS_NewCompartmentAndGlobalObject(cx
, &sandbox_class
, NULL
);
3404 JSAutoEnterCompartment ac
;
3405 if (!ac
.enter(cx
, obj
))
3409 obj
= split_setup(cx
, JS_TRUE
);
3413 if (!lazy
&& !JS_InitStandardClasses(cx
, obj
))
3416 AutoValueRooter
root(cx
, BooleanValue(lazy
));
3417 if (!JS_SetProperty(cx
, obj
, "lazy", root
.jsval_addr()))
3421 obj
= split_outerObject(cx
, obj
);
3424 AutoObjectRooter
objroot(cx
, obj
);
3425 if (!cx
->compartment
->wrap(cx
, objroot
.addr()))
3427 return objroot
.object();
3431 EvalInContext(JSContext
*cx
, uintN argc
, jsval
*vp
)
3434 JSObject
*sobj
= NULL
;
3435 if (!JS_ConvertArguments(cx
, argc
, JS_ARGV(cx
, vp
), "S / o", &str
, &sobj
))
3439 const jschar
*src
= JS_GetStringCharsAndLength(cx
, str
, &srclen
);
3443 bool split
= false, lazy
= false;
3445 if (src
[0] == 'l' && src
[1] == 'a' && src
[2] == 'z' && src
[3] == 'y') {
3449 } else if (srclen
== 5) {
3450 if (src
[0] == 's' && src
[1] == 'p' && src
[2] == 'l' && src
[3] == 'i' && src
[4] == 't') {
3451 split
= lazy
= true;
3457 sobj
= NewSandbox(cx
, lazy
, split
);
3462 *vp
= OBJECT_TO_JSVAL(sobj
);
3466 JSStackFrame
*fp
= JS_GetScriptedCaller(cx
, NULL
);
3468 JSAutoEnterCompartment ac
;
3470 JSObject
*unwrapped
= sobj
->unwrap(&flags
);
3471 if (flags
& JSWrapper::CROSS_COMPARTMENT
) {
3473 if (!ac
.enter(cx
, sobj
))
3477 OBJ_TO_INNER_OBJECT(cx
, sobj
);
3480 if (!(sobj
->getClass()->flags
& JSCLASS_IS_GLOBAL
)) {
3481 JS_ReportError(cx
, "Invalid scope argument to evalcx");
3484 if (!JS_EvaluateUCScript(cx
, sobj
, src
, srclen
,
3485 fp
->script()->filename
,
3486 JS_PCToLineNumber(cx
, fp
->script(), fp
->pc(cx
)),
3491 return cx
->compartment
->wrap(cx
, Valueify(vp
));
3495 EvalInFrame(JSContext
*cx
, uintN argc
, jsval
*vp
)
3497 jsval
*argv
= JS_ARGV(cx
, vp
);
3499 !JSVAL_IS_INT(argv
[0]) ||
3500 !JSVAL_IS_STRING(argv
[1])) {
3501 JS_ReportError(cx
, "Invalid arguments to evalInFrame");
3505 uint32 upCount
= JSVAL_TO_INT(argv
[0]);
3506 JSString
*str
= JSVAL_TO_STRING(argv
[1]);
3508 bool saveCurrent
= (argc
>= 3 && JSVAL_IS_BOOLEAN(argv
[2]))
3509 ? !!(JSVAL_TO_BOOLEAN(argv
[2]))
3512 JS_ASSERT(cx
->hasfp());
3514 FrameRegsIter
fi(cx
);
3515 for (uint32 i
= 0; i
< upCount
; ++i
, ++fi
) {
3516 if (!fi
.fp()->prev())
3520 JSStackFrame
*const fp
= fi
.fp();
3521 if (!JS_IsScriptFrame(cx
, fp
)) {
3522 JS_ReportError(cx
, "cannot eval in non-script frame");
3526 JSStackFrame
*oldfp
= NULL
;
3528 oldfp
= JS_SaveFrameChain(cx
);
3531 const jschar
*chars
= JS_GetStringCharsAndLength(cx
, str
, &length
);
3535 JSBool ok
= JS_EvaluateUCInStackFrame(cx
, fp
, chars
, length
,
3536 fp
->script()->filename
,
3537 JS_PCToLineNumber(cx
, fp
->script(),
3542 JS_RestoreFrameChain(cx
, oldfp
);
3548 ShapeOf(JSContext
*cx
, uintN argc
, jsval
*vp
)
3551 if (argc
< 1 || !JSVAL_IS_OBJECT(v
= JS_ARGV(cx
, vp
)[0])) {
3552 JS_ReportError(cx
, "shapeOf: object expected");
3555 JSObject
*obj
= JSVAL_TO_OBJECT(v
);
3560 if (!obj
->isNative()) {
3561 *vp
= INT_TO_JSVAL(-1);
3564 return JS_NewNumberValue(cx
, obj
->shape(), vp
);
3567 #ifdef JS_THREADSAFE
3570 * Check that t1 comes strictly before t2. The function correctly deals with
3571 * PRIntervalTime wrap-around between t2 and t1 assuming that t2 and t1 stays
3572 * within INT32_MAX from each other. We use MAX_TIMEOUT_INTERVAL to enforce
3576 IsBefore(PRIntervalTime t1
, PRIntervalTime t2
)
3578 return int32(t1
- t2
) < 0;
3582 Sleep_fn(JSContext
*cx
, uintN argc
, jsval
*vp
)
3584 PRIntervalTime t_ticks
;
3591 if (!JS_ValueToNumber(cx
, argc
== 0 ? JSVAL_VOID
: vp
[2], &t_secs
))
3594 /* NB: The next condition also filter out NaNs. */
3595 if (!(t_secs
<= MAX_TIMEOUT_INTERVAL
)) {
3596 JS_ReportError(cx
, "Excessive sleep interval");
3599 t_ticks
= (t_secs
<= 0.0)
3601 : PRIntervalTime(PR_TicksPerSecond() * t_secs
);
3604 JS_YieldRequest(cx
);
3606 JSAutoSuspendRequest
suspended(cx
);
3607 PR_Lock(gWatchdogLock
);
3608 PRIntervalTime to_wakeup
= PR_IntervalNow() + t_ticks
;
3610 PR_WaitCondVar(gSleepWakeup
, t_ticks
);
3613 PRIntervalTime now
= PR_IntervalNow();
3614 if (!IsBefore(now
, to_wakeup
))
3616 t_ticks
= to_wakeup
- now
;
3618 PR_Unlock(gWatchdogLock
);
3623 typedef struct ScatterThreadData ScatterThreadData
;
3624 typedef struct ScatterData ScatterData
;
3626 typedef enum ScatterStatus
{
3632 struct ScatterData
{
3633 ScatterThreadData
*threads
;
3637 ScatterStatus status
;
3640 struct ScatterThreadData
{
3642 ScatterData
*shared
;
3649 DoScatteredWork(JSContext
*cx
, ScatterThreadData
*td
)
3651 jsval
*rval
= &td
->shared
->results
[td
->index
];
3653 if (!JS_CallFunctionValue(cx
, NULL
, td
->fn
, 0, NULL
, rval
)) {
3655 JS_GetPendingException(cx
, rval
);
3656 JS_ClearPendingException(cx
);
3661 RunScatterThread(void *arg
)
3664 ScatterThreadData
*td
;
3668 if (PR_FAILURE
== PR_SetThreadPrivate(gStackBaseThreadIndex
, &stackDummy
))
3671 td
= (ScatterThreadData
*)arg
;
3674 /* Wait for our signal. */
3675 PR_Lock(td
->shared
->lock
);
3676 while ((st
= td
->shared
->status
) == SCATTER_WAIT
)
3677 PR_WaitCondVar(td
->shared
->cvar
, PR_INTERVAL_NO_TIMEOUT
);
3678 PR_Unlock(td
->shared
->lock
);
3680 if (st
== SCATTER_CANCEL
)
3683 /* We are good to go. */
3684 JS_SetContextThread(cx
);
3685 JS_SetNativeStackQuota(cx
, gMaxStackSize
);
3686 JS_BeginRequest(cx
);
3687 DoScatteredWork(cx
, td
);
3689 JS_ClearContextThread(cx
);
3693 * scatter(fnArray) - Call each function in `fnArray` without arguments, each
3694 * in a different thread. When all threads have finished, return an array: the
3695 * return values. Errors are not propagated; if any of the function calls
3696 * fails, the corresponding element in the results array gets the exception
3697 * object, if any, else (undefined).
3700 Scatter(JSContext
*cx
, uintN argc
, jsval
*vp
)
3703 jsuint n
; /* number of threads */
3714 sd
.status
= SCATTER_WAIT
;
3716 if (argc
== 0 || JSVAL_IS_PRIMITIVE(JS_ARGV(cx
, vp
)[0])) {
3717 JS_ReportError(cx
, "the first argument must be an object");
3721 inArr
= JSVAL_TO_OBJECT(JS_ARGV(cx
, vp
)[0]);
3722 ok
= JS_GetArrayLength(cx
, inArr
, &n
);
3728 sd
.lock
= PR_NewLock();
3732 sd
.cvar
= PR_NewCondVar(sd
.lock
);
3736 sd
.results
= (jsval
*) malloc(n
* sizeof(jsval
));
3739 for (i
= 0; i
< n
; i
++) {
3740 sd
.results
[i
] = JSVAL_VOID
;
3741 ok
= JS_AddValueRoot(cx
, &sd
.results
[i
]);
3744 JS_RemoveValueRoot(cx
, &sd
.results
[i
]);
3751 sd
.threads
= (ScatterThreadData
*) malloc(n
* sizeof(ScatterThreadData
));
3754 for (i
= 0; i
< n
; i
++) {
3755 sd
.threads
[i
].index
= i
;
3756 sd
.threads
[i
].shared
= &sd
;
3757 sd
.threads
[i
].thr
= NULL
;
3758 sd
.threads
[i
].cx
= NULL
;
3759 sd
.threads
[i
].fn
= JSVAL_NULL
;
3761 ok
= JS_AddValueRoot(cx
, &sd
.threads
[i
].fn
);
3762 if (ok
&& !JS_GetElement(cx
, inArr
, (jsint
) i
, &sd
.threads
[i
].fn
)) {
3763 JS_RemoveValueRoot(cx
, &sd
.threads
[i
].fn
);
3768 JS_RemoveValueRoot(cx
, &sd
.threads
[i
].fn
);
3775 global
= JS_GetGlobalObject(cx
);
3776 for (i
= 1; i
< n
; i
++) {
3777 JSContext
*newcx
= NewContext(JS_GetRuntime(cx
));
3782 JSAutoRequest
req(newcx
);
3783 JS_SetGlobalObject(newcx
, global
);
3785 JS_ClearContextThread(newcx
);
3786 sd
.threads
[i
].cx
= newcx
;
3789 for (i
= 1; i
< n
; i
++) {
3790 PRThread
*t
= PR_CreateThread(PR_USER_THREAD
,
3798 /* Failed to start thread. */
3800 sd
.status
= SCATTER_CANCEL
;
3801 PR_NotifyAllCondVar(sd
.cvar
);
3804 PR_JoinThread(sd
.threads
[i
].thr
);
3808 sd
.threads
[i
].thr
= t
;
3811 sd
.status
= SCATTER_GO
;
3812 PR_NotifyAllCondVar(sd
.cvar
);
3815 DoScatteredWork(cx
, &sd
.threads
[0]);
3818 JSAutoSuspendRequest
suspended(cx
);
3819 for (i
= 1; i
< n
; i
++) {
3820 PR_JoinThread(sd
.threads
[i
].thr
);
3825 arr
= JS_NewArrayObject(cx
, n
, sd
.results
);
3828 *vp
= OBJECT_TO_JSVAL(arr
);
3835 for (i
= 0; i
< n
; i
++) {
3836 JS_RemoveValueRoot(cx
, &sd
.threads
[i
].fn
);
3837 acx
= sd
.threads
[i
].cx
;
3839 JS_SetContextThread(acx
);
3840 DestroyContext(acx
, true);
3846 for (i
= 0; i
< n
; i
++)
3847 JS_RemoveValueRoot(cx
, &sd
.results
[i
]);
3851 PR_DestroyCondVar(sd
.cvar
);
3853 PR_DestroyLock(sd
.lock
);
3863 InitWatchdog(JSRuntime
*rt
)
3865 JS_ASSERT(!gWatchdogThread
);
3866 gWatchdogLock
= PR_NewLock();
3867 if (gWatchdogLock
) {
3868 gWatchdogWakeup
= PR_NewCondVar(gWatchdogLock
);
3869 if (gWatchdogWakeup
) {
3870 gSleepWakeup
= PR_NewCondVar(gWatchdogLock
);
3873 PR_DestroyCondVar(gWatchdogWakeup
);
3875 PR_DestroyLock(gWatchdogLock
);
3885 PR_Lock(gWatchdogLock
);
3886 thread
= gWatchdogThread
;
3889 * The watchdog thread is running, tell it to terminate waking it up
3892 gWatchdogThread
= NULL
;
3893 PR_NotifyCondVar(gWatchdogWakeup
);
3895 PR_Unlock(gWatchdogLock
);
3897 PR_JoinThread(thread
);
3898 PR_DestroyCondVar(gSleepWakeup
);
3899 PR_DestroyCondVar(gWatchdogWakeup
);
3900 PR_DestroyLock(gWatchdogLock
);
3904 WatchdogMain(void *arg
)
3906 JSRuntime
*rt
= (JSRuntime
*) arg
;
3908 PR_Lock(gWatchdogLock
);
3909 while (gWatchdogThread
) {
3910 PRIntervalTime now
= PR_IntervalNow();
3911 if (gWatchdogHasTimeout
&& !IsBefore(now
, gWatchdogTimeout
)) {
3913 * The timeout has just expired. Trigger the operation callback
3916 gWatchdogHasTimeout
= false;
3917 PR_Unlock(gWatchdogLock
);
3918 CancelExecution(rt
);
3919 PR_Lock(gWatchdogLock
);
3921 /* Wake up any threads doing sleep. */
3922 PR_NotifyAllCondVar(gSleepWakeup
);
3924 PRIntervalTime sleepDuration
= gWatchdogHasTimeout
3925 ? gWatchdogTimeout
- now
3926 : PR_INTERVAL_NO_TIMEOUT
;
3930 PR_WaitCondVar(gWatchdogWakeup
, sleepDuration
);
3931 JS_ASSERT(status
== PR_SUCCESS
);
3934 PR_Unlock(gWatchdogLock
);
3938 ScheduleWatchdog(JSRuntime
*rt
, jsdouble t
)
3941 PR_Lock(gWatchdogLock
);
3942 gWatchdogHasTimeout
= false;
3943 PR_Unlock(gWatchdogLock
);
3947 PRIntervalTime interval
= PRIntervalTime(ceil(t
* PR_TicksPerSecond()));
3948 PRIntervalTime timeout
= PR_IntervalNow() + interval
;
3949 PR_Lock(gWatchdogLock
);
3950 if (!gWatchdogThread
) {
3951 JS_ASSERT(!gWatchdogHasTimeout
);
3952 gWatchdogThread
= PR_CreateThread(PR_USER_THREAD
,
3959 if (!gWatchdogThread
) {
3960 PR_Unlock(gWatchdogLock
);
3963 } else if (!gWatchdogHasTimeout
|| IsBefore(timeout
, gWatchdogTimeout
)) {
3964 PR_NotifyCondVar(gWatchdogWakeup
);
3966 gWatchdogHasTimeout
= true;
3967 gWatchdogTimeout
= timeout
;
3968 PR_Unlock(gWatchdogLock
);
3972 #else /* !JS_THREADSAFE */
3975 static HANDLE gTimerHandle
= 0;
3978 TimerCallback(PVOID lpParameter
, BOOLEAN TimerOrWaitFired
)
3980 CancelExecution((JSRuntime
*) lpParameter
);
3986 AlarmHandler(int sig
)
3988 CancelExecution(gRuntime
);
3994 InitWatchdog(JSRuntime
*rt
)
4003 ScheduleWatchdog(gRuntime
, -1);
4007 ScheduleWatchdog(JSRuntime
*rt
, jsdouble t
)
4011 DeleteTimerQueueTimer(NULL
, gTimerHandle
, NULL
);
4015 !CreateTimerQueueTimer(&gTimerHandle
,
4017 (WAITORTIMERCALLBACK
)TimerCallback
,
4019 DWORD(ceil(t
* 1000.0)),
4021 WT_EXECUTEINTIMERTHREAD
| WT_EXECUTEONLYONCE
)) {
4026 /* FIXME: use setitimer when available for sub-second resolution. */
4029 signal(SIGALRM
, NULL
);
4031 signal(SIGALRM
, AlarmHandler
); /* set the Alarm signal capture */
4038 #endif /* !JS_THREADSAFE */
4041 CancelExecution(JSRuntime
*rt
)
4045 gExitCode
= EXITCODE_TIMEOUT
;
4046 #ifdef JS_THREADSAFE
4047 if (gWorkerThreadPool
)
4048 js::workers::terminateAll(rt
, gWorkerThreadPool
);
4050 JS_TriggerAllOperationCallbacks(rt
);
4052 static const char msg
[] = "Script runs for too long, terminating.\n";
4053 #if defined(XP_UNIX) && !defined(JS_THREADSAFE)
4054 /* It is not safe to call fputs from signals. */
4055 /* Dummy assignment avoids GCC warning on "attribute warn_unused_result" */
4056 ssize_t dummy
= write(2, msg
, sizeof(msg
) - 1);
4064 SetTimeoutValue(JSContext
*cx
, jsdouble t
)
4066 /* NB: The next condition also filter out NaNs. */
4067 if (!(t
<= MAX_TIMEOUT_INTERVAL
)) {
4068 JS_ReportError(cx
, "Excessive timeout value");
4071 gTimeoutInterval
= t
;
4072 if (!ScheduleWatchdog(cx
->runtime
, t
)) {
4073 JS_ReportError(cx
, "Failed to create the watchdog");
4080 Timeout(JSContext
*cx
, uintN argc
, jsval
*vp
)
4083 return JS_NewNumberValue(cx
, gTimeoutInterval
, vp
);
4086 JS_ReportError(cx
, "Wrong number of arguments");
4091 if (!JS_ValueToNumber(cx
, JS_ARGV(cx
, vp
)[0], &t
))
4095 return SetTimeoutValue(cx
, t
);
4099 Elapsed(JSContext
*cx
, uintN argc
, jsval
*vp
)
4103 JSShellContextData
*data
= GetContextData(cx
);
4105 d
= js_IntervalNow() - data
->startTime
;
4106 return JS_NewNumberValue(cx
, d
, vp
);
4108 JS_ReportError(cx
, "Wrong number of arguments");
4113 Parent(JSContext
*cx
, uintN argc
, jsval
*vp
)
4116 JS_ReportError(cx
, "Wrong number of arguments");
4120 jsval v
= JS_ARGV(cx
, vp
)[0];
4121 if (JSVAL_IS_PRIMITIVE(v
)) {
4122 JS_ReportError(cx
, "Only objects have parents!");
4126 JSObject
*parent
= JS_GetParent(cx
, JSVAL_TO_OBJECT(v
));
4127 *vp
= OBJECT_TO_JSVAL(parent
);
4129 /* Outerize if necessary. Embrace the ugliness! */
4131 if (JSObjectOp op
= parent
->getClass()->ext
.outerObject
)
4132 *vp
= OBJECT_TO_JSVAL(op(cx
, parent
));
4141 #include <sys/stat.h>
4144 * Returns a JS_malloc'd string (that the caller needs to JS_free)
4145 * containing the directory (non-leaf) part of |from| prepended to |leaf|.
4146 * If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf.
4147 * Returns NULL to indicate an error.
4150 MakeAbsolutePathname(JSContext
*cx
, const char *from
, const char *leaf
)
4154 const char *slash
= NULL
, *cp
;
4166 /* We were given a leaf or |from| was empty. */
4167 return JS_strdup(cx
, leaf
);
4170 /* Else, we were given a real pathname, return that + the leaf. */
4171 dirlen
= slash
- from
+ 1;
4172 dir
= (char*) JS_malloc(cx
, dirlen
+ strlen(leaf
) + 1);
4176 strncpy(dir
, from
, dirlen
);
4177 strcpy(dir
+ dirlen
, leaf
); /* Note: we can't use strcat here. */
4185 Compile(JSContext
*cx
, uintN argc
, jsval
*vp
)
4188 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_MORE_ARGS_NEEDED
,
4189 "compile", "0", "s");
4192 jsval arg0
= JS_ARGV(cx
, vp
)[0];
4193 if (!JSVAL_IS_STRING(arg0
)) {
4194 const char *typeName
= JS_GetTypeName(cx
, JS_TypeOfValue(cx
, arg0
));
4195 JS_ReportError(cx
, "expected string to compile, got %s", typeName
);
4199 JSString
*scriptContents
= JSVAL_TO_STRING(arg0
);
4200 JSScript
*result
= JS_CompileUCScript(cx
, NULL
, JS_GetStringCharsZ(cx
, scriptContents
),
4201 JS_GetStringLength(scriptContents
), "<string>", 0);
4205 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
4210 Parse(JSContext
*cx
, uintN argc
, jsval
*vp
)
4213 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_MORE_ARGS_NEEDED
,
4214 "compile", "0", "s");
4217 jsval arg0
= JS_ARGV(cx
, vp
)[0];
4218 if (!JSVAL_IS_STRING(arg0
)) {
4219 const char *typeName
= JS_GetTypeName(cx
, JS_TypeOfValue(cx
, arg0
));
4220 JS_ReportError(cx
, "expected string to parse, got %s", typeName
);
4224 JSString
*scriptContents
= JSVAL_TO_STRING(arg0
);
4225 js::Parser
parser(cx
);
4226 parser
.init(JS_GetStringCharsZ(cx
, scriptContents
), JS_GetStringLength(scriptContents
),
4227 "<string>", 0, cx
->findVersion());
4228 if (!parser
.parse(NULL
))
4230 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
4235 Snarf(JSContext
*cx
, uintN argc
, jsval
*vp
)
4238 const char *pathname
;
4244 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[0]);
4247 JSAutoByteString
filename(cx
, str
);
4251 /* Get the currently executing script's name. */
4252 fp
= JS_GetScriptedCaller(cx
, NULL
);
4253 JS_ASSERT(fp
&& fp
->script()->filename
);
4255 pathname
= MakeAbsolutePathname(cx
, fp
->script()->filename
, filename
.ptr());
4259 pathname
= filename
.ptr();
4262 str
= FileAsString(cx
, pathname
);
4264 JS_free(cx
, (void*)pathname
);
4269 *vp
= STRING_TO_JSVAL(str
);
4274 Wrap(JSContext
*cx
, uintN argc
, jsval
*vp
)
4276 jsval v
= argc
> 0 ? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
;
4277 if (JSVAL_IS_PRIMITIVE(v
)) {
4278 JS_SET_RVAL(cx
, vp
, v
);
4282 JSObject
*obj
= JSVAL_TO_OBJECT(v
);
4283 JSObject
*wrapped
= JSWrapper::New(cx
, obj
, obj
->getProto(), obj
->getGlobal(),
4284 &JSWrapper::singleton
);
4288 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(wrapped
));
4293 Serialize(JSContext
*cx
, uintN argc
, jsval
*vp
)
4295 jsval v
= argc
> 0 ? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
;
4298 if (!JS_WriteStructuredClone(cx
, v
, &datap
, &nbytes
, NULL
, NULL
))
4301 JSObject
*arrayobj
= js_CreateTypedArray(cx
, TypedArray::TYPE_UINT8
, nbytes
);
4306 TypedArray
*array
= TypedArray::fromJSObject(arrayobj
);
4307 JS_ASSERT((uintptr_t(array
->data
) & 7) == 0);
4308 memcpy(array
->data
, datap
, nbytes
);
4310 JS_SET_RVAL(cx
, vp
, OBJECT_TO_JSVAL(arrayobj
));
4315 Deserialize(JSContext
*cx
, uintN argc
, jsval
*vp
)
4317 jsval v
= argc
> 0 ? JS_ARGV(cx
, vp
)[0] : JSVAL_VOID
;
4319 if (JSVAL_IS_PRIMITIVE(v
) || !js_IsTypedArray((obj
= JSVAL_TO_OBJECT(v
)))) {
4320 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_INVALID_ARGS
, "deserialize");
4323 TypedArray
*array
= TypedArray::fromJSObject(obj
);
4324 if ((array
->byteLength
& 7) != 0) {
4325 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_INVALID_ARGS
, "deserialize");
4328 if ((uintptr_t(array
->data
) & 7) != 0) {
4329 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_BAD_ALIGNMENT
);
4333 if (!JS_ReadStructuredClone(cx
, (uint64
*) array
->data
, array
->byteLength
,
4334 JS_STRUCTURED_CLONE_VERSION
, &v
, NULL
, NULL
)) {
4337 JS_SET_RVAL(cx
, vp
, v
);
4342 MJitStats(JSContext
*cx
, uintN argc
, jsval
*vp
)
4345 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(cx
->runtime
->mjitMemoryUsed
));
4347 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
4353 StringStats(JSContext
*cx
, uintN argc
, jsval
*vp
)
4355 JS_SET_RVAL(cx
, vp
, INT_TO_JSVAL(cx
->runtime
->stringMemoryUsed
));
4359 static JSFunctionSpec shell_functions
[] = {
4360 JS_FN("version", Version
, 0,0),
4361 JS_FN("revertVersion", RevertVersion
, 0,0),
4362 JS_FN("options", Options
, 0,0),
4363 JS_FN("load", Load
, 1,0),
4364 JS_FN("evaluate", Evaluate
, 1,0),
4365 JS_FN("run", Run
, 1,0),
4366 JS_FN("readline", ReadLine
, 0,0),
4367 JS_FN("print", Print
, 0,0),
4368 JS_FN("putstr", PutStr
, 0,0),
4369 JS_FN("dateNow", Now
, 0,0),
4370 JS_FN("help", Help
, 0,0),
4371 JS_FN("quit", Quit
, 0,0),
4372 JS_FN("assertEq", AssertEq
, 2,0),
4373 JS_FN("assertJit", AssertJit
, 0,0),
4374 JS_FN("gc", ::GC
, 0,0),
4376 JS_FN("gcstats", GCStats
, 0,0),
4378 JS_FN("gcparam", GCParameter
, 2,0),
4379 JS_FN("countHeap", CountHeap
, 0,0),
4380 JS_FN("makeFinalizeObserver", MakeFinalizeObserver
, 0,0),
4381 JS_FN("finalizeCount", FinalizeCount
, 0,0),
4383 JS_FN("gczeal", GCZeal
, 1,0),
4385 JS_FN("setDebug", SetDebug
, 1,0),
4386 JS_FN("setDebuggerHandler", SetDebuggerHandler
, 1,0),
4387 JS_FN("setThrowHook", SetThrowHook
, 1,0),
4388 JS_FN("trap", Trap
, 3,0),
4389 JS_FN("untrap", Untrap
, 2,0),
4390 JS_FN("line2pc", LineToPC
, 0,0),
4391 JS_FN("pc2line", PCToLine
, 0,0),
4392 JS_FN("stackQuota", StackQuota
, 0,0),
4393 JS_FN("stringsAreUTF8", StringsAreUTF8
, 0,0),
4394 JS_FN("testUTF8", TestUTF8
, 1,0),
4395 JS_FN("throwError", ThrowError
, 0,0),
4397 JS_FN("dis", Disassemble
, 1,0),
4398 JS_FN("disfile", DisassFile
, 1,0),
4399 JS_FN("dissrc", DisassWithSrc
, 1,0),
4400 JS_FN("dumpHeap", DumpHeap
, 0,0),
4401 JS_FN("dumpObject", DumpObject
, 1,0),
4402 JS_FN("notes", Notes
, 1,0),
4403 JS_FN("tracing", Tracing
, 0,0),
4404 JS_FN("stats", DumpStats
, 1,0),
4407 JS_FN("cvtargs", ConvertArgs
, 0,0),
4409 JS_FN("build", BuildDate
, 0,0),
4410 JS_FN("clear", Clear
, 0,0),
4411 JS_FN("intern", Intern
, 1,0),
4412 JS_FN("clone", Clone
, 1,0),
4413 JS_FN("getpda", GetPDA
, 1,0),
4414 JS_FN("getslx", GetSLX
, 1,0),
4415 JS_FN("toint32", ToInt32
, 1,0),
4416 JS_FN("evalcx", EvalInContext
, 1,0),
4417 JS_FN("evalInFrame", EvalInFrame
, 2,0),
4418 JS_FN("shapeOf", ShapeOf
, 1,0),
4419 #ifdef MOZ_CALLGRIND
4420 JS_FN("startCallgrind", js_StartCallgrind
, 0,0),
4421 JS_FN("stopCallgrind", js_StopCallgrind
, 0,0),
4422 JS_FN("dumpCallgrind", js_DumpCallgrind
, 1,0),
4425 JS_FN("startVtune", js_StartVtune
, 1,0),
4426 JS_FN("stopVtune", js_StopVtune
, 0,0),
4427 JS_FN("pauseVtune", js_PauseVtune
, 0,0),
4428 JS_FN("resumeVtune", js_ResumeVtune
, 0,0),
4431 JS_FN("startTraceVis", StartTraceVisNative
, 1,0),
4432 JS_FN("stopTraceVis", StopTraceVisNative
, 0,0),
4435 JS_FN("arrayInfo", js_ArrayInfo
, 1,0),
4437 #ifdef JS_THREADSAFE
4438 JS_FN("sleep", Sleep_fn
, 1,0),
4439 JS_FN("scatter", Scatter
, 1,0),
4441 JS_FN("snarf", Snarf
, 0,0),
4442 JS_FN("read", Snarf
, 0,0),
4443 JS_FN("compile", Compile
, 1,0),
4444 JS_FN("parse", Parse
, 1,0),
4445 JS_FN("timeout", Timeout
, 1,0),
4446 JS_FN("elapsed", Elapsed
, 0,0),
4447 JS_FN("parent", Parent
, 1,0),
4448 JS_FN("wrap", Wrap
, 1,0),
4449 JS_FN("serialize", Serialize
, 1,0),
4450 JS_FN("deserialize", Deserialize
, 1,0),
4452 JS_FN("mjitstats", MJitStats
, 0,0),
4454 JS_FN("stringstats", StringStats
, 0,0),
4458 static const char shell_help_header
[] =
4459 "Command Description\n"
4460 "======= ===========\n";
4462 static const char *const shell_help_messages
[] = {
4463 "version([number]) Get or force a script compilation version number",
4464 "revertVersion() Revert previously set version number",
4465 "options([option ...]) Get or toggle JavaScript options",
4466 "load(['foo.js' ...]) Load files named by string arguments",
4467 "evaluate(code) Evaluate code as though it were the contents of a file",
4469 " Run the file named by the first argument, returning the number of\n"
4470 " of milliseconds spent compiling and executing it",
4471 "readline() Read a single line from stdin",
4472 "print([exp ...]) Evaluate and print expressions",
4473 "putstr([exp]) Evaluate and print expression without newline",
4474 "dateNow() Return the current time with sub-ms precision",
4475 "help([name ...]) Display usage and help messages",
4476 "quit() Quit the shell",
4477 "assertEq(actual, expected[, msg])\n"
4478 " Throw if the first two arguments are not the same (both +0 or both -0,\n"
4479 " both NaN, or non-zero and ===)",
4480 "assertJit() Throw if the calling function failed to JIT\n",
4481 "gc() Run the garbage collector",
4483 "gcstats() Print garbage collector statistics",
4485 "gcparam(name, value)\n"
4486 " Wrapper for JS_SetGCParameter. The name must be either 'maxBytes' or\n"
4487 " 'maxMallocBytes' and the value must be convertable to a positive uint32",
4488 "countHeap([start[, kind]])\n"
4489 " Count the number of live GC things in the heap or things reachable from\n"
4490 " start when it is given and is not null. kind is either 'all' (default) to\n"
4491 " count all things or one of 'object', 'double', 'string', 'function',\n"
4492 " 'qname', 'namespace', 'xml' to count only things of that kind",
4493 "makeFinalizeObserver()\n"
4494 " get a special object whose finalization increases the counter returned\n"
4495 " by the finalizeCount function",
4497 " return the current value of the finalization counter that is incremented\n"
4498 " each time an object returned by the makeFinalizeObserver is finalized",
4500 "gczeal(level) How zealous the garbage collector should be",
4502 "setDebug(debug) Set debug mode",
4503 "setDebuggerHandler(f) Set handler for debugger keyword to f",
4504 "setThrowHook(f) Set throw hook to f",
4505 "trap([fun, [pc,]] exp) Trap bytecode execution",
4506 "untrap(fun[, pc]) Remove a trap",
4507 "line2pc([fun,] line) Map line number to PC",
4508 "pc2line(fun[, pc]) Map PC to line number",
4509 "stackQuota([number]) Query/set script stack quota",
4510 "stringsAreUTF8() Check if strings are UTF-8 encoded",
4511 "testUTF8(mode) Perform UTF-8 tests (modes are 1 to 4)",
4512 "throwError() Throw an error from JS_ReportError",
4514 "dis([fun]) Disassemble functions into bytecodes",
4515 "disfile('foo.js') Disassemble script file into bytecodes\n"
4516 " dis and disfile take these options as preceeding string arguments\n"
4517 " \"-r\" (disassemble recursively)\n"
4518 " \"-l\" (show line numbers)",
4519 "dissrc([fun]) Disassemble functions with source lines",
4520 "dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])\n"
4521 " Interface to JS_DumpHeap with output sent to file",
4522 "dumpObject() Dump an internal representation of an object",
4523 "notes([fun]) Show source notes for functions",
4524 "tracing([true|false|filename]) Turn bytecode execution tracing on/off.\n"
4525 " With filename, send to file.\n",
4526 "stats([string ...]) Dump 'arena', 'atom', 'global' stats",
4529 "cvtargs(arg1..., arg12) Test argument formatter",
4531 "build() Show build date and time",
4532 "clear([obj]) Clear properties of object",
4533 "intern(str) Internalize str in the atom table",
4534 "clone(fun[, scope]) Clone function object",
4535 "getpda(obj) Get the property descriptors for obj",
4536 "getslx(obj) Get script line extent",
4537 "toint32(n) Testing hook for JS_ValueToInt32",
4539 " Evaluate s in optional sandbox object o\n"
4540 " if (s == '' && !o) return new o with eager standard classes\n"
4541 " if (s == 'lazy' && !o) return new o with lazy standard classes\n"
4542 " if (s == 'split' && !o) return new split-object o with lazy standard classes",
4543 "evalInFrame(n,str,save) Evaluate 'str' in the nth up frame.\n"
4544 " If 'save' (default false), save the frame chain",
4545 "shapeOf(obj) Get the shape of obj (an implementation detail)",
4546 #ifdef MOZ_CALLGRIND
4547 "startCallgrind() Start callgrind instrumentation",
4548 "stopCallgrind() Stop callgrind instrumentation",
4549 "dumpCallgrind([name]) Dump callgrind counters",
4552 "startVtune([filename]) Start vtune instrumentation",
4553 "stopVtune() Stop vtune instrumentation",
4554 "pauseVtune() Pause vtune collection",
4555 "resumeVtune() Resume vtune collection",
4558 "startTraceVis(filename) Start TraceVis recording (stops any current recording)",
4559 "stopTraceVis() Stop TraceVis recording",
4562 "arrayInfo(a1, a2, ...) Report statistics about arrays",
4564 #ifdef JS_THREADSAFE
4565 "sleep(dt) Sleep for dt seconds",
4566 "scatter(fns) Call functions concurrently (ignoring errors)",
4568 "snarf(filename) Read filename into returned string",
4569 "read(filename) Synonym for snarf",
4570 "compile(code) Compiles a string to bytecode, potentially throwing",
4571 "parse(code) Parses a string, potentially throwing",
4572 "timeout([seconds])\n"
4573 " Get/Set the limit in seconds for the execution time for the current context.\n"
4574 " A negative value (default) means that the execution time is unlimited.",
4575 "elapsed() Execution time elapsed for the current context.",
4576 "parent(obj) Returns the parent of obj.\n",
4577 "wrap(obj) Wrap an object into a noop wrapper.\n",
4578 "serialize(sd) Serialize sd using JS_WriteStructuredClone. Returns a TypedArray.\n",
4579 "deserialize(a) Deserialize data generated by serialize.\n",
4581 "mjitstats() Return stats on mjit memory usage.\n",
4583 "stringstats() Return stats on string memory usage.\n"
4584 #ifdef MOZ_PROFILING
4585 "startProfiling() Start a profiling session.\n"
4586 " Profiler must be running with programatic sampling\n"
4587 "stopProfiling() Stop a running profiling session"
4591 /* Help messages must match shell functions. */
4592 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages
) + 1 ==
4593 JS_ARRAY_LENGTH(shell_functions
));
4599 const char *const *m
;
4602 /* Each message must begin with "function_name(" prefix. */
4603 for (m
= shell_help_messages
; m
!= JS_ARRAY_END(shell_help_messages
); ++m
) {
4604 lp
= strchr(*m
, '(');
4606 JS_ASSERT(memcmp(shell_functions
[m
- shell_help_messages
].name
,
4611 # define CheckHelpMessages() ((void) 0)
4615 Help(JSContext
*cx
, uintN argc
, jsval
*vp
)
4618 int did_header
, did_something
;
4623 fprintf(gOutFile
, "%s\n", JS_GetImplementationVersion());
4625 fputs(shell_help_header
, gOutFile
);
4626 for (i
= 0; shell_functions
[i
].name
; i
++)
4627 fprintf(gOutFile
, "%s\n", shell_help_messages
[i
]);
4630 jsval
*argv
= JS_ARGV(cx
, vp
);
4631 for (i
= 0; i
< argc
; i
++) {
4633 type
= JS_TypeOfValue(cx
, argv
[i
]);
4634 if (type
== JSTYPE_FUNCTION
) {
4635 fun
= JS_ValueToFunction(cx
, argv
[i
]);
4636 str
= fun
->atom
? ATOM_TO_STRING(fun
->atom
) : NULL
;
4637 } else if (type
== JSTYPE_STRING
) {
4638 str
= JSVAL_TO_STRING(argv
[i
]);
4643 JSFlatString
*flatStr
= JS_FlattenString(cx
, str
);
4646 for (j
= 0; shell_functions
[j
].name
; j
++) {
4647 if (JS_FlatStringEqualsAscii(flatStr
, shell_functions
[j
].name
)) {
4650 fputs(shell_help_header
, gOutFile
);
4653 fprintf(gOutFile
, "%s\n", shell_help_messages
[j
]);
4658 if (!did_something
) {
4659 str
= JS_ValueToString(cx
, argv
[i
]);
4662 fputs("Sorry, no help for ", gErrFile
);
4663 JS_FileEscapedString(gErrFile
, str
, 0);
4664 putc('\n', gErrFile
);
4668 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
4673 split_setup(JSContext
*cx
, JSBool evalcx
)
4675 JSObject
*outer
, *inner
, *arguments
;
4677 outer
= split_create_outer(cx
);
4680 AutoObjectRooter
root(cx
, outer
);
4682 JS_SetGlobalObject(cx
, outer
);
4684 inner
= split_create_inner(cx
, outer
);
4689 if (!JS_DefineFunctions(cx
, inner
, shell_functions
) ||
4690 !JS_DefineProfilingFunctions(cx
, inner
)) {
4694 /* Create a dummy arguments object. */
4695 arguments
= JS_NewArrayObject(cx
, 0, NULL
);
4697 !JS_DefineProperty(cx
, inner
, "arguments", OBJECT_TO_JSVAL(arguments
),
4703 JS_ClearScope(cx
, outer
);
4705 #ifndef LAZY_STANDARD_CLASSES
4706 if (!JS_InitStandardClasses(cx
, inner
))
4714 * Define a JS object called "it". Give it class operations that printf why
4715 * they're being called for tutorial purposes.
4718 ITS_COLOR
, ITS_HEIGHT
, ITS_WIDTH
, ITS_FUNNY
, ITS_ARRAY
, ITS_RDONLY
,
4719 ITS_CUSTOM
, ITS_CUSTOMRDONLY
4723 its_getter(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
4725 jsval
*val
= (jsval
*) JS_GetPrivate(cx
, obj
);
4726 *vp
= val
? *val
: JSVAL_VOID
;
4731 its_setter(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, jsval
*vp
)
4733 jsval
*val
= (jsval
*) JS_GetPrivate(cx
, obj
);
4741 JS_ReportOutOfMemory(cx
);
4745 if (!JS_AddValueRoot(cx
, val
)) {
4750 if (!JS_SetPrivate(cx
, obj
, (void*)val
)) {
4751 JS_RemoveValueRoot(cx
, val
);
4760 static JSPropertySpec its_props
[] = {
4761 {"color", ITS_COLOR
, JSPROP_ENUMERATE
, NULL
, NULL
},
4762 {"height", ITS_HEIGHT
, JSPROP_ENUMERATE
, NULL
, NULL
},
4763 {"width", ITS_WIDTH
, JSPROP_ENUMERATE
, NULL
, NULL
},
4764 {"funny", ITS_FUNNY
, JSPROP_ENUMERATE
, NULL
, NULL
},
4765 {"array", ITS_ARRAY
, JSPROP_ENUMERATE
, NULL
, NULL
},
4766 {"rdonly", ITS_RDONLY
, JSPROP_READONLY
, NULL
, NULL
},
4767 {"custom", ITS_CUSTOM
, JSPROP_ENUMERATE
,
4768 its_getter
, its_setter
},
4769 {"customRdOnly", ITS_CUSTOMRDONLY
, JSPROP_ENUMERATE
| JSPROP_READONLY
,
4770 its_getter
, its_setter
},
4771 {NULL
,0,0,NULL
,NULL
}
4775 its_bindMethod(JSContext
*cx
, uintN argc
, jsval
*vp
)
4780 JSObject
*thisobj
= JS_THIS_OBJECT(cx
, vp
);
4782 if (!JS_ConvertArguments(cx
, argc
, JS_ARGV(cx
, vp
), "So", &name
, &method
))
4785 *vp
= OBJECT_TO_JSVAL(method
);
4787 if (JS_TypeOfValue(cx
, *vp
) != JSTYPE_FUNCTION
) {
4788 JSAutoByteString
nameBytes(cx
, name
);
4790 JSString
*valstr
= JS_ValueToString(cx
, *vp
);
4792 JSAutoByteString
valBytes(cx
, valstr
);
4794 JS_ReportError(cx
, "can't bind method %s to non-callable object %s",
4795 nameBytes
.ptr(), valBytes
.ptr());
4803 if (!JS_ValueToId(cx
, STRING_TO_JSVAL(name
), &id
))
4806 if (!JS_DefinePropertyById(cx
, thisobj
, id
, *vp
, NULL
, NULL
, JSPROP_ENUMERATE
))
4809 return JS_SetParent(cx
, method
, thisobj
);
4812 static JSFunctionSpec its_methods
[] = {
4813 {"bindMethod", its_bindMethod
, 2,0},
4817 #ifdef JSD_LOWLEVEL_SOURCE
4819 * This facilitates sending source to JSD (the debugger system) in the shell
4820 * where the source is loaded using the JSFILE hack in jsscan. The function
4821 * below is used as a callback for the jsdbgapi JS_SetSourceHandler hook.
4822 * A more normal embedding (e.g. mozilla) loads source itself and can send
4823 * source directly to JSD without using this hook scheme.
4826 SendSourceToJSDebugger(const char *filename
, uintN lineno
,
4827 jschar
*str
, size_t length
,
4828 void **listenerTSData
, JSDContext
* jsdc
)
4830 JSDSourceText
*jsdsrc
= (JSDSourceText
*) *listenerTSData
;
4834 filename
= "typein";
4836 jsdsrc
= JSD_NewSourceText(jsdc
, filename
);
4838 jsdsrc
= JSD_FindSourceForURL(jsdc
, filename
);
4839 if (jsdsrc
&& JSD_SOURCE_PARTIAL
!=
4840 JSD_GetSourceStatus(jsdc
, jsdsrc
)) {
4846 jsdsrc
= JSD_AppendUCSourceText(jsdc
,jsdsrc
, str
, length
,
4847 JSD_SOURCE_PARTIAL
);
4849 *listenerTSData
= jsdsrc
;
4851 #endif /* JSD_LOWLEVEL_SOURCE */
4853 static JSBool its_noisy
; /* whether to be noisy when finalizing it */
4854 static JSBool its_enum_fail
;/* whether to fail when enumerating it */
4857 its_addProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
4862 IdToString
idString(cx
, id
);
4863 fprintf(gOutFile
, "adding its property %s,", idString
.getBytes());
4864 ToString
valueString(cx
, *vp
);
4865 fprintf(gOutFile
, " initial value %s\n", valueString
.getBytes());
4870 its_delProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
4875 IdToString
idString(cx
, id
);
4876 fprintf(gOutFile
, "deleting its property %s,", idString
.getBytes());
4877 ToString
valueString(cx
, *vp
);
4878 fprintf(gOutFile
, " initial value %s\n", valueString
.getBytes());
4883 its_getProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
4888 IdToString
idString(cx
, id
);
4889 fprintf(gOutFile
, "getting its property %s,", idString
.getBytes());
4890 ToString
valueString(cx
, *vp
);
4891 fprintf(gOutFile
, " initial value %s\n", valueString
.getBytes());
4896 its_setProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, jsval
*vp
)
4898 IdToString
idString(cx
, id
);
4900 fprintf(gOutFile
, "setting its property %s,", idString
.getBytes());
4901 ToString
valueString(cx
, *vp
);
4902 fprintf(gOutFile
, " new value %s\n", valueString
.getBytes());
4905 if (!JSID_IS_ATOM(id
))
4908 if (!strcmp(idString
.getBytes(), "noisy"))
4909 JS_ValueToBoolean(cx
, *vp
, &its_noisy
);
4910 else if (!strcmp(idString
.getBytes(), "enum_fail"))
4911 JS_ValueToBoolean(cx
, *vp
, &its_enum_fail
);
4917 * Its enumerator, implemented using the "new" enumerate API,
4921 its_enumerate(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
4922 jsval
*statep
, jsid
*idp
)
4927 case JSENUMERATE_INIT
:
4928 case JSENUMERATE_INIT_ALL
:
4930 fprintf(gOutFile
, "enumerate its properties\n");
4932 iterator
= JS_NewPropertyIterator(cx
, obj
);
4936 *statep
= OBJECT_TO_JSVAL(iterator
);
4938 *idp
= INT_TO_JSID(0);
4941 case JSENUMERATE_NEXT
:
4942 if (its_enum_fail
) {
4943 JS_ReportError(cx
, "its enumeration failed");
4947 iterator
= (JSObject
*) JSVAL_TO_OBJECT(*statep
);
4948 if (!JS_NextProperty(cx
, iterator
, idp
))
4951 if (!JSID_IS_VOID(*idp
))
4955 case JSENUMERATE_DESTROY
:
4956 /* Allow our iterator object to be GC'd. */
4957 *statep
= JSVAL_NULL
;
4965 its_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
4969 IdToString
idString(cx
, id
);
4970 fprintf(gOutFile
, "resolving its property %s, flags {%s,%s,%s}\n",
4971 idString
.getBytes(),
4972 (flags
& JSRESOLVE_QUALIFIED
) ? "qualified" : "",
4973 (flags
& JSRESOLVE_ASSIGNING
) ? "assigning" : "",
4974 (flags
& JSRESOLVE_DETECTING
) ? "detecting" : "");
4980 its_convert(JSContext
*cx
, JSObject
*obj
, JSType type
, jsval
*vp
)
4983 fprintf(gOutFile
, "converting it to %s type\n", JS_GetTypeName(cx
, type
));
4988 its_finalize(JSContext
*cx
, JSObject
*obj
)
4992 fprintf(gOutFile
, "finalizing it\n");
4993 rootedVal
= (jsval
*) JS_GetPrivate(cx
, obj
);
4995 JS_RemoveValueRoot(cx
, rootedVal
);
4996 JS_SetPrivate(cx
, obj
, NULL
);
5001 static JSClass its_class
= {
5002 "It", JSCLASS_NEW_RESOLVE
| JSCLASS_NEW_ENUMERATE
| JSCLASS_HAS_PRIVATE
,
5003 its_addProperty
, its_delProperty
, its_getProperty
, its_setProperty
,
5004 (JSEnumerateOp
)its_enumerate
, (JSResolveOp
)its_resolve
,
5005 its_convert
, its_finalize
,
5006 JSCLASS_NO_OPTIONAL_MEMBERS
5009 JSErrorFormatString jsShell_ErrorFormatString
[JSErr_Limit
] = {
5010 #define MSG_DEF(name, number, count, exception, format) \
5011 { format, count, JSEXN_ERR } ,
5012 #include "jsshell.msg"
5016 static const JSErrorFormatString
*
5017 my_GetErrorMessage(void *userRef
, const char *locale
, const uintN errorNumber
)
5019 if ((errorNumber
> 0) && (errorNumber
< JSShellErr_Limit
))
5020 return &jsShell_ErrorFormatString
[errorNumber
];
5025 my_ErrorReporter(JSContext
*cx
, const char *message
, JSErrorReport
*report
)
5032 fprintf(gErrFile
, "%s\n", message
);
5036 /* Conditionally ignore reported warnings. */
5037 if (JSREPORT_IS_WARNING(report
->flags
) && !reportWarnings
)
5041 if (report
->filename
)
5042 prefix
= JS_smprintf("%s:", report
->filename
);
5043 if (report
->lineno
) {
5045 prefix
= JS_smprintf("%s%u: ", tmp
? tmp
: "", report
->lineno
);
5048 if (JSREPORT_IS_WARNING(report
->flags
)) {
5050 prefix
= JS_smprintf("%s%swarning: ",
5052 JSREPORT_IS_STRICT(report
->flags
) ? "strict " : "");
5056 /* embedded newlines -- argh! */
5057 while ((ctmp
= strchr(message
, '\n')) != 0) {
5060 fputs(prefix
, gErrFile
);
5061 fwrite(message
, 1, ctmp
- message
, gErrFile
);
5065 /* If there were no filename or lineno, the prefix might be empty */
5067 fputs(prefix
, gErrFile
);
5068 fputs(message
, gErrFile
);
5070 if (!report
->linebuf
) {
5071 fputc('\n', gErrFile
);
5075 /* report->linebuf usually ends with a newline. */
5076 n
= strlen(report
->linebuf
);
5077 fprintf(gErrFile
, ":\n%s%s%s%s",
5080 (n
> 0 && report
->linebuf
[n
-1] == '\n') ? "" : "\n",
5082 n
= report
->tokenptr
- report
->linebuf
;
5083 for (i
= j
= 0; i
< n
; i
++) {
5084 if (report
->linebuf
[i
] == '\t') {
5085 for (k
= (j
+ 8) & ~7; j
< k
; j
++) {
5086 fputc('.', gErrFile
);
5090 fputc('.', gErrFile
);
5093 fputs("^\n", gErrFile
);
5095 if (!JSREPORT_IS_WARNING(report
->flags
)) {
5096 if (report
->errorNumber
== JSMSG_OUT_OF_MEMORY
) {
5097 gExitCode
= EXITCODE_OUT_OF_MEMORY
;
5099 gExitCode
= EXITCODE_RUNTIME_ERROR
;
5102 JS_free(cx
, prefix
);
5105 #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
5107 Exec(JSContext
*cx
, uintN argc
, jsval
*vp
)
5110 const char *name
, **nargv
;
5117 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
5119 fun
= JS_ValueToFunction(cx
, vp
[0]);
5127 /* nargc + 1 accounts for the terminating NULL. */
5128 nargv
= new (char *)[nargc
+ 1];
5131 memset(nargv
, 0, sizeof(nargv
[0]) * (nargc
+ 1));
5133 jsval
*argv
= JS_ARGV(cx
, vp
);
5134 for (i
= 0; i
< nargc
; i
++) {
5135 str
= (i
== 0) ? ATOM_TO_STRING(fun
->atom
) : JS_ValueToString(cx
, argv
[i
-1]);
5140 nargv
[i
] = JS_EncodeString(cx
, str
);
5152 (void) execvp(name
, (char **)nargv
);
5156 while (waitpid(pid
, &status
, 0) < 0 && errno
== EINTR
)
5163 for (i
= 0; i
< nargc
; i
++)
5164 JS_free(cx
, nargv
[i
]);
5171 global_enumerate(JSContext
*cx
, JSObject
*obj
)
5173 #ifdef LAZY_STANDARD_CLASSES
5174 return JS_EnumerateStandardClasses(cx
, obj
);
5181 global_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
5184 #ifdef LAZY_STANDARD_CLASSES
5187 if (!ResolveClass(cx
, obj
, id
, &resolved
))
5195 #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
5196 if (!(flags
& JSRESOLVE_QUALIFIED
)) {
5198 * Do this expensive hack only for unoptimized Unix builds, which are
5199 * not used for benchmarking.
5201 char *path
, *comp
, *full
;
5206 if (!JSVAL_IS_STRING(id
))
5208 path
= getenv("PATH");
5211 path
= JS_strdup(cx
, path
);
5214 JSAutoByteString
name(cx
, JSVAL_TO_STRING(id
));
5218 for (comp
= strtok(path
, ":"); comp
; comp
= strtok(NULL
, ":")) {
5219 if (*comp
!= '\0') {
5220 full
= JS_smprintf("%s/%s", comp
, name
.ptr());
5222 JS_ReportOutOfMemory(cx
);
5227 full
= (char *)name
;
5229 found
= (access(full
, X_OK
) == 0);
5233 fun
= JS_DefineFunction(cx
, obj
, name
, Exec
, 0,
5249 JSClass global_class
= {
5250 "global", JSCLASS_NEW_RESOLVE
| JSCLASS_GLOBAL_FLAGS
| JSCLASS_HAS_PRIVATE
,
5251 JS_PropertyStub
, JS_PropertyStub
,
5252 JS_PropertyStub
, JS_StrictPropertyStub
,
5253 global_enumerate
, (JSResolveOp
) global_resolve
,
5254 JS_ConvertStub
, its_finalize
,
5255 JSCLASS_NO_OPTIONAL_MEMBERS
5259 env_setProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool strict
, jsval
*vp
)
5261 /* XXX porting may be easy, but these don't seem to supply setenv by default */
5262 #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS
5265 IdToString
idstr(cx
, id
, JS_TRUE
);
5268 ToString
valstr(cx
, *vp
, JS_TRUE
);
5271 #if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX
5273 char *waste
= JS_smprintf("%s=%s", idstr
.getBytes(), valstr
.getBytes());
5275 JS_ReportOutOfMemory(cx
);
5281 * HPUX9 at least still has the bad old non-copying putenv.
5283 * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
5284 * that will crash if you pass it an auto char array (so it must place
5285 * its argument directly in the char *environ[] array).
5287 JS_smprintf_free(waste
);
5291 rv
= setenv(idstr
.getBytes(), valstr
.getBytes(), 1);
5294 JS_ReportError(cx
, "can't set env variable %s to %s", idstr
.getBytes(), valstr
.getBytes());
5297 *vp
= valstr
.getJSVal();
5298 #endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */
5303 env_enumerate(JSContext
*cx
, JSObject
*obj
)
5305 static JSBool reflected
;
5306 char **evp
, *name
, *value
;
5313 for (evp
= (char **)JS_GetPrivate(cx
, obj
); (name
= *evp
) != NULL
; evp
++) {
5314 value
= strchr(name
, '=');
5318 valstr
= JS_NewStringCopyZ(cx
, value
);
5322 ok
= JS_DefineProperty(cx
, obj
, name
, STRING_TO_JSVAL(valstr
),
5323 NULL
, NULL
, JSPROP_ENUMERATE
);
5330 reflected
= JS_TRUE
;
5335 env_resolve(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
5339 const char *name
, *value
;
5341 if (flags
& JSRESOLVE_ASSIGNING
)
5344 IdToString
idstr(cx
, id
, JS_TRUE
);
5348 name
= idstr
.getBytes();
5349 value
= getenv(name
);
5351 valstr
= JS_NewStringCopyZ(cx
, value
);
5354 if (!JS_DefineProperty(cx
, obj
, name
, STRING_TO_JSVAL(valstr
),
5355 NULL
, NULL
, JSPROP_ENUMERATE
)) {
5363 static JSClass env_class
= {
5364 "environment", JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
,
5365 JS_PropertyStub
, JS_PropertyStub
,
5366 JS_PropertyStub
, env_setProperty
,
5367 env_enumerate
, (JSResolveOp
) env_resolve
,
5368 JS_ConvertStub
, NULL
,
5369 JSCLASS_NO_OPTIONAL_MEMBERS
5373 * Avoid a reentrancy hazard.
5375 * The non-JS_THREADSAFE shell uses a signal handler to implement timeout().
5376 * The JS engine is not really reentrant, but JS_TriggerAllOperationCallbacks
5377 * is mostly safe--the only danger is that we might interrupt JS_NewContext or
5378 * JS_DestroyContext while the context list is being modified. Therefore we
5379 * disable the signal handler around calls to those functions.
5381 #ifdef JS_THREADSAFE
5382 # define WITH_SIGNALS_DISABLED(x) x
5384 # define WITH_SIGNALS_DISABLED(x) \
5386 ScheduleWatchdog(gRuntime, -1); \
5388 ScheduleWatchdog(gRuntime, gTimeoutInterval); \
5393 NewContext(JSRuntime
*rt
)
5396 WITH_SIGNALS_DISABLED(cx
= JS_NewContext(rt
, gStackChunkSize
));
5400 JSShellContextData
*data
= NewContextData();
5402 DestroyContext(cx
, false);
5406 JS_SetContextPrivate(cx
, data
);
5407 JS_SetErrorReporter(cx
, my_ErrorReporter
);
5408 JS_SetVersion(cx
, JSVERSION_LATEST
);
5409 SetContextOptions(cx
);
5411 JS_ToggleOptions(cx
, JSOPTION_JIT
);
5412 if (enableMethodJit
)
5413 JS_ToggleOptions(cx
, JSOPTION_METHODJIT
);
5418 DestroyContext(JSContext
*cx
, bool withGC
)
5420 JSShellContextData
*data
= GetContextData(cx
);
5421 JS_SetContextPrivate(cx
, NULL
);
5423 WITH_SIGNALS_DISABLED(withGC
? JS_DestroyContext(cx
) : JS_DestroyContextNoGC(cx
));
5427 NewGlobalObject(JSContext
*cx
)
5429 JSObject
*glob
= JS_NewCompartmentAndGlobalObject(cx
, &global_class
, NULL
);
5433 JSAutoEnterCompartment ac
;
5434 if (!ac
.enter(cx
, glob
))
5437 #ifdef LAZY_STANDARD_CLASSES
5438 JS_SetGlobalObject(cx
, glob
);
5440 if (!JS_InitStandardClasses(cx
, glob
))
5443 #ifdef JS_HAS_CTYPES
5444 if (!JS_InitCTypesClass(cx
, glob
))
5447 if (!JS::RegisterPerfMeasurement(cx
, glob
))
5449 if (!JS_DefineFunctions(cx
, glob
, shell_functions
) ||
5450 !JS_DefineProfilingFunctions(cx
, glob
)) {
5454 JSObject
*it
= JS_DefineObject(cx
, glob
, "it", &its_class
, NULL
, 0);
5457 if (!JS_DefineProperties(cx
, it
, its_props
))
5459 if (!JS_DefineFunctions(cx
, it
, its_methods
))
5462 if (!JS_DefineProperty(cx
, glob
, "custom", JSVAL_VOID
, its_getter
,
5465 if (!JS_DefineProperty(cx
, glob
, "customRdOnly", JSVAL_VOID
, its_getter
,
5466 its_setter
, JSPROP_READONLY
))
5473 Shell(JSContext
*cx
, int argc
, char **argv
, char **envp
)
5475 JSAutoRequest
ar(cx
);
5477 JSObject
*glob
= NewGlobalObject(cx
);
5481 JSAutoEnterCompartment ac
;
5482 if (!ac
.enter(cx
, glob
))
5485 JSObject
*envobj
= JS_DefineObject(cx
, glob
, "environment", &env_class
, NULL
, 0);
5486 if (!envobj
|| !JS_SetPrivate(cx
, envobj
, envp
))
5491 * XXX A command line option to enable debugging (or not) would be good
5493 jsdc
= JSD_DebuggerOnForUser(rt
, NULL
, NULL
);
5496 JSD_JSContextInUse(jsdc
, cx
);
5497 #ifdef JSD_LOWLEVEL_SOURCE
5498 JS_SetSourceHandler(rt
, SendSourceToJSDebugger
, jsdc
);
5499 #endif /* JSD_LOWLEVEL_SOURCE */
5500 #ifdef JSDEBUGGER_JAVA_UI
5501 jsdjc
= JSDJ_CreateContext();
5504 JSDJ_SetJSDContext(jsdjc
, jsdc
);
5505 java_env
= JSDJ_CreateJavaVMAndStartDebugger(jsdjc
);
5507 * XXX This would be the place to wait for the debugger to start.
5508 * Waiting would be nice in general, but especially when a js file
5509 * is passed on the cmd line.
5511 #endif /* JSDEBUGGER_JAVA_UI */
5512 #ifdef JSDEBUGGER_C_UI
5513 jsdbc
= JSDB_InitDebugger(rt
, jsdc
, 0);
5514 #endif /* JSDEBUGGER_C_UI */
5515 #endif /* JSDEBUGGER */
5517 #ifdef JS_THREADSAFE
5518 class ShellWorkerHooks
: public js::workers::WorkerHooks
{
5520 JSObject
*newGlobalObject(JSContext
*cx
) {
5521 return NewGlobalObject(cx
);
5524 ShellWorkerHooks hooks
;
5525 if (!JS_AddNamedObjectRoot(cx
, &gWorkers
, "Workers") ||
5526 (gWorkerThreadPool
= js::workers::init(cx
, &hooks
, glob
, &gWorkers
)) == NULL
) {
5531 int result
= ProcessArgs(cx
, glob
, argv
, argc
);
5533 #ifdef JS_THREADSAFE
5534 js::workers::finish(cx
, gWorkerThreadPool
);
5535 JS_RemoveObjectRoot(cx
, &gWorkers
);
5542 #ifdef JSDEBUGGER_C_UI
5544 JSDB_TermDebugger(jsdc
);
5545 #endif /* JSDEBUGGER_C_UI */
5546 JSD_DebuggerOff(jsdc
);
5548 #endif /* JSDEBUGGER */
5554 MaybeOverrideOutFileFromEnv(const char* const envVar
,
5558 const char* outPath
= getenv(envVar
);
5559 if (!outPath
|| !*outPath
|| !(*outFile
= fopen(outPath
, "w"))) {
5560 *outFile
= defaultOut
;
5565 main(int argc
, char **argv
, char **envp
)
5573 #ifdef JSDEBUGGER_JAVA_UI
5577 #ifdef JSDEBUGGER_C_UI
5579 #endif /* JSDEBUGGER_C_UI */
5580 #endif /* JSDEBUGGER */
5583 const char *crash_option
= getenv("XRE_NO_WINDOWS_CRASH_DIALOG");
5584 if (crash_option
&& strncmp(crash_option
, "1", 1)) {
5585 DWORD oldmode
= SetErrorMode(SEM_NOGPFAULTERRORBOX
);
5586 SetErrorMode(oldmode
| SEM_NOGPFAULTERRORBOX
);
5591 CheckHelpMessages();
5592 #ifdef HAVE_SETLOCALE
5593 setlocale(LC_ALL
, "");
5596 #ifdef JS_THREADSAFE
5597 if (PR_FAILURE
== PR_NewThreadPrivateIndex(&gStackBaseThreadIndex
, NULL
) ||
5598 PR_FAILURE
== PR_SetThreadPrivate(gStackBaseThreadIndex
, &stackDummy
)) {
5602 gStackBase
= (jsuword
) &stackDummy
;
5606 /* these streams are normally line buffered on OS/2 and need a \n, *
5607 * so we need to unbuffer then to get a reasonable prompt */
5612 MaybeOverrideOutFileFromEnv("JS_STDERR", stderr
, &gErrFile
);
5613 MaybeOverrideOutFileFromEnv("JS_STDOUT", stdout
, &gOutFile
);
5619 // Set the timer calibration delay count to 0 so we get high
5620 // resolution right away, which we need for precise benchmarking.
5621 extern int CALIBRATION_DELAY_COUNT
;
5622 CALIBRATION_DELAY_COUNT
= 0;
5625 rt
= JS_NewRuntime(160L * 1024L * 1024L);
5629 if (!InitWatchdog(rt
))
5632 cx
= NewContext(rt
);
5636 JS_SetOptions(cx
, JS_GetOptions(cx
) | JSOPTION_ANONFUNFIX
);
5637 JS_SetGCParameterForThread(cx
, JSGC_MAX_CODE_CACHE_BYTES
, 16 * 1024 * 1024);
5639 result
= Shell(cx
, argc
, argv
, envp
);
5641 DestroyContext(cx
, true);
5645 JS_DestroyRuntime(rt
);