1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
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 ***** */
75 #ifdef JSDEBUGGER_JAVA_UI
77 #endif /* JSDEBUGGER_JAVA_UI */
78 #ifdef JSDEBUGGER_C_UI
80 #endif /* JSDEBUGGER_C_UI */
81 #endif /* JSDEBUGGER */
85 #include <sys/types.h>
89 #if defined(XP_WIN) || defined(XP_OS2)
90 #include <io.h> /* for isatty() */
93 typedef enum JSShellExitCode
{
94 EXITCODE_RUNTIME_ERROR
= 3,
95 EXITCODE_FILE_NOT_FOUND
= 4,
96 EXITCODE_OUT_OF_MEMORY
= 5
99 size_t gStackChunkSize
= 8192;
101 /* Assume that we can not use more than 5e5 bytes of C stack by default. */
102 static size_t gMaxStackSize
= 500000;
103 static jsuword gStackBase
;
105 static size_t gScriptStackQuota
= JS_DEFAULT_SCRIPT_STACK_QUOTA
;
107 static JSBool gEnableBranchCallback
= JS_FALSE
;
108 static uint32 gBranchCount
;
109 static uint32 gBranchLimit
;
112 JSBool gQuitting
= JS_FALSE
;
113 FILE *gErrFile
= NULL
;
114 FILE *gOutFile
= NULL
;
116 static JSBool reportWarnings
= JS_TRUE
;
117 static JSBool compileOnly
= JS_FALSE
;
119 typedef enum JSShellErrNum
{
120 #define MSG_DEF(name, number, count, exception, format) \
122 #include "jsshell.msg"
128 static const JSErrorFormatString
*
129 my_GetErrorMessage(void *userRef
, const char *locale
, const uintN errorNumber
);
131 split_setup(JSContext
*cx
);
135 extern char *readline(const char *prompt
);
136 extern void add_history(char *line
);
141 GetLine(JSContext
*cx
, char *bufp
, FILE *file
, const char *prompt
) {
144 * Use readline only if file is stdin, because there's no way to specify
145 * another handle. Are other filehandles interactive?
148 char *linep
= readline(prompt
);
151 if (linep
[0] != '\0')
155 bufp
+= strlen(bufp
);
162 fprintf(gOutFile
, prompt
);
164 if (!fgets(line
, sizeof line
, file
))
172 my_BranchCallback(JSContext
*cx
, JSScript
*script
)
174 if (++gBranchCount
== gBranchLimit
) {
176 if (script
->filename
)
177 fprintf(gErrFile
, "%s:", script
->filename
);
178 fprintf(gErrFile
, "%u: script branch callback (%u callbacks)\n",
179 script
->lineno
, gBranchLimit
);
181 fprintf(gErrFile
, "native branch callback (%u callbacks)\n",
188 if ((gBranchCount
& 0xff) == 1) {
190 if ((gBranchCount
& 0x3fff) == 1)
201 SetContextOptions(JSContext
*cx
)
205 if (gMaxStackSize
== 0) {
207 * Disable checking for stack overflow if limit is zero.
211 #if JS_STACK_GROWTH_DIRECTION > 0
212 stackLimit
= gStackBase
+ gMaxStackSize
;
214 stackLimit
= gStackBase
- gMaxStackSize
;
217 JS_SetThreadStackLimit(cx
, stackLimit
);
218 JS_SetScriptStackQuota(cx
, gScriptStackQuota
);
219 if (gEnableBranchCallback
) {
220 JS_SetBranchCallback(cx
, my_BranchCallback
);
221 JS_ToggleOptions(cx
, JSOPTION_NATIVE_BRANCH_CALLBACK
);
226 Process(JSContext
*cx
, JSObject
*obj
, char *filename
, JSBool forceTTY
)
238 if (forceTTY
|| !filename
|| strcmp(filename
, "-") == 0) {
241 file
= fopen(filename
, "r");
243 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
244 JSSMSG_CANT_OPEN
, filename
, strerror(errno
));
245 gExitCode
= EXITCODE_FILE_NOT_FOUND
;
250 SetContextOptions(cx
);
252 if (!forceTTY
&& !isatty(fileno(file
))) {
254 * It's not interactive - just execute it.
256 * Support the UNIX #! shell hack; gobble the first line if it starts
257 * with '#'. TODO - this isn't quite compatible with sharp variables,
258 * as a legal js program (using sharp variables) might start with '#'.
259 * But that would require multi-character lookahead.
261 int ch
= fgetc(file
);
263 while((ch
= fgetc(file
)) != EOF
) {
264 if (ch
== '\n' || ch
== '\r')
269 script
= JS_CompileFileHandle(cx
, obj
, filename
, file
);
272 (void)JS_ExecuteScript(cx
, obj
, script
, &result
);
273 JS_DestroyScript(cx
, script
);
281 /* It's an interactive filehandle; drop into read-eval-print loop. */
289 * Accumulate lines until we get a 'compilable unit' - one that either
290 * generates an error (before running out of source) or that compiles
291 * cleanly. This should be whenever we get a complete statement that
292 * coincides with the end of a line.
296 if (!GetLine(cx
, bufp
, file
, startline
== lineno
? "js> " : "")) {
300 bufp
+= strlen(bufp
);
302 } while (!JS_BufferIsCompilableUnit(cx
, obj
, buffer
, strlen(buffer
)));
304 /* Clear any pending exception from previous failed compiles. */
305 JS_ClearPendingException(cx
);
306 script
= JS_CompileScript(cx
, obj
, buffer
, strlen(buffer
), "typein",
310 ok
= JS_ExecuteScript(cx
, obj
, script
, &result
);
311 if (ok
&& !JSVAL_IS_VOID(result
)) {
312 str
= JS_ValueToString(cx
, result
);
314 fprintf(gOutFile
, "%s\n", JS_GetStringBytes(str
));
319 JS_DestroyScript(cx
, script
);
321 } while (!hitEOF
&& !gQuitting
);
322 fprintf(gOutFile
, "\n");
331 fprintf(gErrFile
, "%s\n", JS_GetImplementationVersion());
332 fprintf(gErrFile
, "usage: js [-zKPswWxCi] [-b branchlimit] [-c stackchunksize] [-o option] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] "
336 "[scriptfile] [scriptarg...]\n");
344 {"strict", JSOPTION_STRICT
},
345 {"werror", JSOPTION_WERROR
},
346 {"atline", JSOPTION_ATLINE
},
347 {"xml", JSOPTION_XML
},
348 {"relimit", JSOPTION_RELIMIT
},
349 {"anonfunfix", JSOPTION_ANONFUNFIX
},
353 extern JSClass global_class
;
356 ProcessArgs(JSContext
*cx
, JSObject
*obj
, char **argv
, int argc
)
360 char *filename
= NULL
;
361 JSBool isInteractive
= JS_TRUE
;
362 JSBool forceTTY
= JS_FALSE
;
365 * Scan past all optional arguments so we can create the arguments object
366 * before processing any -f options, which must interleave properly with
367 * -v and -w options. This requires two passes, and without getopt, we'll
368 * have to keep the option logic here and in the second for loop in sync.
370 for (i
= 0; i
< argc
; i
++) {
371 if (argv
[i
][0] != '-' || argv
[i
][1] == '\0') {
375 switch (argv
[i
][1]) {
392 * Create arguments early and define it to root it, so it's safe from any
393 * GC calls nested below, and so it is available to -f <file> arguments.
395 argsObj
= JS_NewArrayObject(cx
, 0, NULL
);
398 if (!JS_DefineProperty(cx
, obj
, "arguments", OBJECT_TO_JSVAL(argsObj
),
404 for (j
= 0; j
< length
; j
++) {
405 JSString
*str
= JS_NewStringCopyZ(cx
, argv
[i
++]);
408 if (!JS_DefineElement(cx
, argsObj
, j
, STRING_TO_JSVAL(str
),
409 NULL
, NULL
, JSPROP_ENUMERATE
)) {
414 for (i
= 0; i
< argc
; i
++) {
415 if (argv
[i
][0] != '-' || argv
[i
][1] == '\0') {
416 filename
= argv
[i
++];
417 isInteractive
= JS_FALSE
;
421 switch (argv
[i
][1]) {
426 JS_SetVersion(cx
, (JSVersion
) atoi(argv
[i
]));
433 JS_SetGCZeal(cx
, atoi(argv
[i
]));
438 reportWarnings
= JS_TRUE
;
442 reportWarnings
= JS_FALSE
;
446 JS_ToggleOptions(cx
, JSOPTION_STRICT
);
450 JS_ToggleOptions(cx
, JSOPTION_RELIMIT
);
454 JS_ToggleOptions(cx
, JSOPTION_XML
);
461 for (j
= 0; js_options
[j
].name
; ++j
) {
462 if (strcmp(js_options
[j
].name
, argv
[i
]) == 0) {
463 JS_ToggleOptions(cx
, js_options
[j
].flag
);
470 if (JS_GET_CLASS(cx
, JS_GetPrototype(cx
, obj
)) != &global_class
) {
473 if (!JS_SealObject(cx
, obj
, JS_TRUE
))
475 gobj
= JS_NewObject(cx
, &global_class
, NULL
, NULL
);
478 if (!JS_SetPrototype(cx
, gobj
, obj
))
480 JS_SetParent(cx
, gobj
, NULL
);
481 JS_SetGlobalObject(cx
, gobj
);
487 gBranchLimit
= atoi(argv
[++i
]);
488 gEnableBranchCallback
= (gBranchLimit
!= 0);
492 /* set stack chunk size */
493 gStackChunkSize
= atoi(argv
[++i
]);
500 Process(cx
, obj
, argv
[i
], JS_FALSE
);
503 * XXX: js -f foo.js should interpret foo.js and then
504 * drop into interactive mode, but that breaks the test
505 * harness. Just execute foo.js for now.
507 isInteractive
= JS_FALSE
;
517 /* Pass a filename of -e to imitate PERL */
518 JS_EvaluateScript(cx
, obj
, argv
[i
], strlen(argv
[i
]),
521 isInteractive
= JS_FALSE
;
526 compileOnly
= JS_TRUE
;
527 isInteractive
= JS_FALSE
;
531 isInteractive
= forceTTY
= JS_TRUE
;
538 /* Set maximum stack size. */
539 gMaxStackSize
= atoi(argv
[i
]);
543 obj
= split_setup(cx
);
557 if (filename
|| isInteractive
)
558 Process(cx
, obj
, filename
, forceTTY
);
563 Version(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
565 if (argc
> 0 && JSVAL_IS_INT(argv
[0]))
566 *rval
= INT_TO_JSVAL(JS_SetVersion(cx
, (JSVersion
) JSVAL_TO_INT(argv
[0])));
568 *rval
= INT_TO_JSVAL(JS_GetVersion(cx
));
573 Options(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
582 for (i
= 0; i
< argc
; i
++) {
583 str
= JS_ValueToString(cx
, argv
[i
]);
586 opt
= JS_GetStringBytes(str
);
587 for (j
= 0; js_options
[j
].name
; j
++) {
588 if (strcmp(js_options
[j
].name
, opt
) == 0) {
589 optset
|= js_options
[j
].flag
;
594 optset
= JS_ToggleOptions(cx
, optset
);
598 while (optset
!= 0) {
600 optset
&= optset
- 1;
602 for (j
= 0; js_options
[j
].name
; j
++) {
603 if (js_options
[j
].flag
== flag
) {
604 names
= JS_sprintf_append(names
, "%s%s",
605 names
? "," : "", js_options
[j
].name
);
614 JS_ReportOutOfMemory(cx
);
618 str
= JS_NewString(cx
, names
, strlen(names
));
623 *rval
= STRING_TO_JSVAL(str
);
628 Load(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
632 const char *filename
;
638 for (i
= 0; i
< argc
; i
++) {
639 str
= JS_ValueToString(cx
, argv
[i
]);
642 argv
[i
] = STRING_TO_JSVAL(str
);
643 filename
= JS_GetStringBytes(str
);
645 oldopts
= JS_GetOptions(cx
);
646 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
);
647 script
= JS_CompileFile(cx
, obj
, filename
);
652 ? JS_ExecuteScript(cx
, obj
, script
, &result
)
654 JS_DestroyScript(cx
, script
);
656 JS_SetOptions(cx
, oldopts
);
665 * function readline()
666 * Provides a hook for scripts to read a line from stdin.
669 ReadLine(JSContext
*cx
, uintN argc
, jsval
*vp
)
674 size_t bufsize
, buflength
, gotlength
;
681 buf
= (char *) JS_malloc(cx
, bufsize
);
685 sawNewline
= JS_FALSE
;
687 js_fgets(buf
+ buflength
, bufsize
- buflength
, from
)) > 0) {
688 buflength
+= gotlength
;
691 if (buf
[buflength
- 1] == '\n') {
692 buf
[buflength
- 1] = '\0';
693 sawNewline
= JS_TRUE
;
695 } else if (buflength
< bufsize
- 1) {
699 /* Else, grow our buffer for another pass. */
701 if (bufsize
> buflength
) {
702 tmp
= (char *) JS_realloc(cx
, buf
, bufsize
);
704 JS_ReportOutOfMemory(cx
);
716 /* Treat the empty string specially. */
717 if (buflength
== 0) {
718 *vp
= feof(from
) ? JSVAL_NULL
: JS_GetEmptyStringValue(cx
);
723 /* Shrink the buffer to the real size. */
724 tmp
= (char *) JS_realloc(cx
, buf
, buflength
);
733 * Turn buf into a JSString. Note that buflength includes the trailing null
736 str
= JS_NewString(cx
, buf
, sawNewline
? buflength
- 1 : buflength
);
742 *vp
= STRING_TO_JSVAL(str
);
747 Print(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
753 for (i
= 0; i
< argc
; i
++) {
754 str
= JS_ValueToString(cx
, argv
[i
]);
757 bytes
= JS_EncodeString(cx
, str
);
760 fprintf(gOutFile
, "%s%s", i
? " " : "", bytes
);
764 fputc('\n', gOutFile
);
771 Help(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
774 Quit(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
777 JSJ_SimpleShutdown();
780 JS_ConvertArguments(cx
, argc
, argv
,"/ i", &gExitCode
);
787 GC(JSContext
*cx
, uintN argc
, jsval
*vp
)
793 preBytes
= rt
->gcBytes
;
796 fprintf(gOutFile
, "before %lu, after %lu, break %08lx\n",
797 (unsigned long)preBytes
, (unsigned long)rt
->gcBytes
,
799 (unsigned long)sbrk(0)
805 js_DumpGCStats(rt
, stdout
);
812 GCParameter(JSContext
*cx
, uintN argc
, jsval
*vp
)
816 const char *paramName
;
820 argv
= JS_ARGV(cx
, vp
);
821 str
= JS_ValueToString(cx
, argv
[0]);
824 argv
[0] = STRING_TO_JSVAL(str
);
825 paramName
= JS_GetStringBytes(str
);
828 if (strcmp(paramName
, "maxBytes") == 0) {
829 param
= JSGC_MAX_BYTES
;
830 } else if (strcmp(paramName
, "maxMallocBytes") == 0) {
831 param
= JSGC_MAX_MALLOC_BYTES
;
834 "the first argument argument must be either maxBytes "
835 "or maxMallocBytes");
839 if (!JS_ValueToECMAUint32(cx
, argv
[1], &value
))
843 "the second argument must be convertable to uint32 with "
847 JS_SetGCParameter(cx
->runtime
, param
, value
);
854 GCZeal(JSContext
*cx
, uintN argc
, jsval
*vp
)
858 if (!JS_ValueToECMAUint32(cx
, vp
[2], &zeal
))
860 JS_SetGCZeal(cx
, zeal
);
864 #endif /* JS_GC_ZEAL */
866 typedef struct JSCountHeapNode JSCountHeapNode
;
868 struct JSCountHeapNode
{
871 JSCountHeapNode
*next
;
874 typedef struct JSCountHeapTracer
{
876 JSDHashTable visited
;
878 JSCountHeapNode
*traceList
;
879 JSCountHeapNode
*recycleList
;
883 CountHeapNotify(JSTracer
*trc
, void *thing
, uint32 kind
)
885 JSCountHeapTracer
*countTracer
;
886 JSDHashEntryStub
*entry
;
887 JSCountHeapNode
*node
;
889 JS_ASSERT(trc
->callback
== CountHeapNotify
);
890 countTracer
= (JSCountHeapTracer
*)trc
;
891 if (!countTracer
->ok
)
894 entry
= (JSDHashEntryStub
*)
895 JS_DHashTableOperate(&countTracer
->visited
, thing
, JS_DHASH_ADD
);
897 JS_ReportOutOfMemory(trc
->context
);
898 countTracer
->ok
= JS_FALSE
;
905 node
= countTracer
->recycleList
;
907 countTracer
->recycleList
= node
->next
;
909 node
= (JSCountHeapNode
*) JS_malloc(trc
->context
, sizeof *node
);
911 countTracer
->ok
= JS_FALSE
;
917 node
->next
= countTracer
->traceList
;
918 countTracer
->traceList
= node
;
922 CountHeap(JSContext
*cx
, uintN argc
, jsval
*vp
)
925 int32 startTraceKind
;
930 JSCountHeapTracer countTracer
;
931 JSCountHeapNode
*node
;
934 static const struct {
937 } traceKindNames
[] = {
939 { "object", JSTRACE_OBJECT
},
940 { "double", JSTRACE_DOUBLE
},
941 { "string", JSTRACE_STRING
},
942 #if JS_HAS_XML_SUPPORT
943 { "namespace", JSTRACE_NAMESPACE
},
944 { "qname", JSTRACE_QNAME
},
945 { "xml", JSTRACE_XML
},
952 v
= JS_ARGV(cx
, vp
)[0];
953 if (JSVAL_IS_TRACEABLE(v
)) {
954 startThing
= JSVAL_TO_TRACEABLE(v
);
955 startTraceKind
= JSVAL_TRACE_KIND(v
);
956 } else if (v
!= JSVAL_NULL
) {
958 "the first argument is not null or a heap-allocated "
966 str
= JS_ValueToString(cx
, JS_ARGV(cx
, vp
)[1]);
969 bytes
= JS_GetStringBytes(str
);
973 if (strcmp(bytes
, traceKindNames
[i
].name
) == 0) {
974 traceKind
= traceKindNames
[i
].kind
;
977 if (++i
== JS_ARRAY_LENGTH(traceKindNames
)) {
978 JS_ReportError(cx
, "trace kind name '%s' is unknown", bytes
);
984 JS_TRACER_INIT(&countTracer
.base
, cx
, CountHeapNotify
);
985 if (!JS_DHashTableInit(&countTracer
.visited
, JS_DHashGetStubOps(),
986 NULL
, sizeof(JSDHashEntryStub
),
987 JS_DHASH_DEFAULT_CAPACITY(100))) {
988 JS_ReportOutOfMemory(cx
);
991 countTracer
.ok
= JS_TRUE
;
992 countTracer
.traceList
= NULL
;
993 countTracer
.recycleList
= NULL
;
996 JS_TraceRuntime(&countTracer
.base
);
998 JS_SET_TRACING_NAME(&countTracer
.base
, "root");
999 JS_CallTracer(&countTracer
.base
, startThing
, startTraceKind
);
1003 while ((node
= countTracer
.traceList
) != NULL
) {
1004 if (traceKind
== -1 || node
->kind
== traceKind
)
1006 countTracer
.traceList
= node
->next
;
1007 node
->next
= countTracer
.recycleList
;
1008 countTracer
.recycleList
= node
;
1009 JS_TraceChildren(&countTracer
.base
, node
->thing
, node
->kind
);
1011 while ((node
= countTracer
.recycleList
) != NULL
) {
1012 countTracer
.recycleList
= node
->next
;
1015 JS_DHashTableFinish(&countTracer
.visited
);
1017 return countTracer
.ok
&& JS_NewNumberValue(cx
, (jsdouble
) counter
, vp
);
1021 ValueToScript(JSContext
*cx
, jsval v
)
1026 if (!JSVAL_IS_PRIMITIVE(v
) &&
1027 JS_GET_CLASS(cx
, JSVAL_TO_OBJECT(v
)) == &js_ScriptClass
) {
1028 script
= (JSScript
*) JS_GetPrivate(cx
, JSVAL_TO_OBJECT(v
));
1030 fun
= JS_ValueToFunction(cx
, v
);
1033 script
= FUN_SCRIPT(fun
);
1039 GetTrapArgs(JSContext
*cx
, uintN argc
, jsval
*argv
, JSScript
**scriptp
,
1046 *scriptp
= cx
->fp
->down
->script
;
1051 if (!JSVAL_IS_PRIMITIVE(v
) &&
1052 (JS_GET_CLASS(cx
, JSVAL_TO_OBJECT(v
)) == &js_FunctionClass
||
1053 JS_GET_CLASS(cx
, JSVAL_TO_OBJECT(v
)) == &js_ScriptClass
)) {
1054 script
= ValueToScript(cx
, v
);
1060 if (argc
> intarg
) {
1061 if (!JS_ValueToInt32(cx
, argv
[intarg
], ip
))
1069 TrapHandler(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsval
*rval
,
1073 JSStackFrame
*caller
;
1075 str
= (JSString
*) closure
;
1076 caller
= JS_GetScriptedCaller(cx
, NULL
);
1077 if (!JS_EvaluateScript(cx
, caller
->scopeChain
,
1078 JS_GetStringBytes(str
), JS_GetStringLength(str
),
1079 caller
->script
->filename
, caller
->script
->lineno
,
1081 return JSTRAP_ERROR
;
1083 if (!JSVAL_IS_VOID(*rval
))
1084 return JSTRAP_RETURN
;
1085 return JSTRAP_CONTINUE
;
1089 Trap(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1096 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_TRAP_USAGE
);
1100 str
= JS_ValueToString(cx
, argv
[argc
]);
1103 argv
[argc
] = STRING_TO_JSVAL(str
);
1104 if (!GetTrapArgs(cx
, argc
, argv
, &script
, &i
))
1106 return JS_SetTrap(cx
, script
, script
->code
+ i
, TrapHandler
, str
);
1110 Untrap(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1115 if (!GetTrapArgs(cx
, argc
, argv
, &script
, &i
))
1117 JS_ClearTrap(cx
, script
, script
->code
+ i
, NULL
, NULL
);
1122 LineToPC(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1130 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_LINE2PC_USAGE
);
1133 script
= cx
->fp
->down
->script
;
1134 if (!GetTrapArgs(cx
, argc
, argv
, &script
, &i
))
1136 lineno
= (i
== 0) ? script
->lineno
: (uintN
)i
;
1137 pc
= JS_LineNumberToPC(cx
, script
, lineno
);
1140 *rval
= INT_TO_JSVAL(PTRDIFF(pc
, script
->code
, jsbytecode
));
1145 PCToLine(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1151 if (!GetTrapArgs(cx
, argc
, argv
, &script
, &i
))
1153 lineno
= JS_PCToLineNumber(cx
, script
, script
->code
+ i
);
1156 *rval
= INT_TO_JSVAL(lineno
);
1163 UpdateSwitchTableBounds(JSScript
*script
, uintN offset
,
1164 uintN
*start
, uintN
*end
)
1171 pc
= script
->code
+ offset
;
1174 case JSOP_TABLESWITCHX
:
1175 jmplen
= JUMPX_OFFSET_LEN
;
1177 case JSOP_TABLESWITCH
:
1178 jmplen
= JUMP_OFFSET_LEN
;
1181 low
= GET_JUMP_OFFSET(pc
);
1182 pc
+= JUMP_OFFSET_LEN
;
1183 high
= GET_JUMP_OFFSET(pc
);
1184 pc
+= JUMP_OFFSET_LEN
;
1188 case JSOP_LOOKUPSWITCHX
:
1189 jmplen
= JUMPX_OFFSET_LEN
;
1191 case JSOP_LOOKUPSWITCH
:
1192 jmplen
= JUMP_OFFSET_LEN
;
1197 jmplen
+= JUMP_OFFSET_LEN
;
1201 /* [condswitch] switch does not have any jump or lookup tables. */
1202 JS_ASSERT(op
== JSOP_CONDSWITCH
);
1206 *start
= (uintN
)(pc
- script
->code
);
1207 *end
= *start
+ (uintN
)(n
* jmplen
);
1211 SrcNotes(JSContext
*cx
, JSScript
*script
)
1213 uintN offset
, delta
, caseOff
, switchTableStart
, switchTableEnd
;
1214 jssrcnote
*notes
, *sn
;
1221 fprintf(gOutFile
, "\nSource notes:\n");
1223 notes
= SCRIPT_NOTES(script
);
1224 switchTableEnd
= switchTableStart
= 0;
1225 for (sn
= notes
; !SN_IS_TERMINATOR(sn
); sn
= SN_NEXT(sn
)) {
1226 delta
= SN_DELTA(sn
);
1228 type
= (JSSrcNoteType
) SN_TYPE(sn
);
1229 name
= js_SrcNoteSpec
[type
].name
;
1230 if (type
== SRC_LABEL
) {
1231 /* Check if the source note is for a switch case. */
1232 if (switchTableStart
<= offset
&& offset
< switchTableEnd
) {
1235 JS_ASSERT(script
->code
[offset
] == JSOP_NOP
);
1238 fprintf(gOutFile
, "%3u: %5u [%4u] %-8s",
1239 PTRDIFF(sn
, notes
, jssrcnote
), offset
, delta
, name
);
1242 fprintf(gOutFile
, " lineno %u", (uintN
) js_GetSrcNoteOffset(sn
, 0));
1245 fprintf(gOutFile
, " cond %u update %u tail %u",
1246 (uintN
) js_GetSrcNoteOffset(sn
, 0),
1247 (uintN
) js_GetSrcNoteOffset(sn
, 1),
1248 (uintN
) js_GetSrcNoteOffset(sn
, 2));
1251 fprintf(gOutFile
, " else %u elseif %u",
1252 (uintN
) js_GetSrcNoteOffset(sn
, 0),
1253 (uintN
) js_GetSrcNoteOffset(sn
, 1));
1261 fprintf(gOutFile
, " offset %u", (uintN
) js_GetSrcNoteOffset(sn
, 0));
1264 case SRC_LABELBRACE
:
1265 case SRC_BREAK2LABEL
:
1266 case SRC_CONT2LABEL
:
1267 index
= js_GetSrcNoteOffset(sn
, 0);
1268 JS_GET_SCRIPT_ATOM(script
, index
, atom
);
1269 JS_ASSERT(ATOM_IS_STRING(atom
));
1270 str
= ATOM_TO_STRING(atom
);
1271 fprintf(gOutFile
, " atom %u (", index
);
1272 js_FileEscapedString(gOutFile
, str
, 0);
1273 putc(')', gOutFile
);
1280 index
= js_GetSrcNoteOffset(sn
, 0);
1281 JS_GET_SCRIPT_OBJECT(script
, index
, obj
);
1282 fun
= (JSFunction
*) JS_GetPrivate(cx
, obj
);
1283 str
= JS_DecompileFunction(cx
, fun
, JS_DONT_PRETTY_PRINT
);
1284 bytes
= str
? JS_GetStringBytes(str
) : "N/A";
1285 fprintf(gOutFile
, " function %u (%s)", index
, bytes
);
1289 fprintf(gOutFile
, " length %u", (uintN
) js_GetSrcNoteOffset(sn
, 0));
1290 caseOff
= (uintN
) js_GetSrcNoteOffset(sn
, 1);
1292 fprintf(gOutFile
, " first case offset %u", caseOff
);
1293 UpdateSwitchTableBounds(script
, offset
,
1294 &switchTableStart
, &switchTableEnd
);
1297 delta
= (uintN
) js_GetSrcNoteOffset(sn
, 0);
1299 if (script
->main
[offset
] == JSOP_LEAVEBLOCK
)
1300 fprintf(gOutFile
, " stack depth %u", delta
);
1302 fprintf(gOutFile
, " guard delta %u", delta
);
1307 fputc('\n', gOutFile
);
1312 Notes(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1317 for (i
= 0; i
< argc
; i
++) {
1318 script
= ValueToScript(cx
, argv
[i
]);
1322 SrcNotes(cx
, script
);
1327 JS_STATIC_ASSERT(JSTN_CATCH
== 0);
1328 JS_STATIC_ASSERT(JSTN_FINALLY
== 1);
1329 JS_STATIC_ASSERT(JSTN_ITER
== 2);
1331 static const char* const TryNoteNames
[] = { "catch", "finally", "iter" };
1334 TryNotes(JSContext
*cx
, JSScript
*script
)
1336 JSTryNote
*tn
, *tnlimit
;
1338 if (script
->trynotesOffset
== 0)
1341 tn
= JS_SCRIPT_TRYNOTES(script
)->vector
;
1342 tnlimit
= tn
+ JS_SCRIPT_TRYNOTES(script
)->length
;
1343 fprintf(gOutFile
, "\nException table:\n"
1344 "kind stack start end\n");
1346 JS_ASSERT(tn
->kind
< JS_ARRAY_LENGTH(TryNoteNames
));
1347 fprintf(gOutFile
, " %-7s %6u %8u %8u\n",
1348 TryNoteNames
[tn
->kind
], tn
->stackDepth
,
1349 tn
->start
, tn
->start
+ tn
->length
);
1350 } while (++tn
!= tnlimit
);
1355 Disassemble(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1362 JSVAL_IS_STRING(argv
[0]) &&
1363 !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv
[0])), "-l")) {
1369 for (i
= 0; i
< argc
; i
++) {
1370 script
= ValueToScript(cx
, argv
[i
]);
1374 if (VALUE_IS_FUNCTION(cx
, argv
[i
])) {
1375 JSFunction
*fun
= JS_ValueToFunction(cx
, argv
[i
]);
1376 if (fun
&& (fun
->flags
& JSFUN_FLAGS_MASK
)) {
1377 uint16 flags
= fun
->flags
;
1378 fputs("flags:", stdout
);
1380 #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
1385 SHOW_FLAG(BOUND_METHOD
);
1386 SHOW_FLAG(HEAVYWEIGHT
);
1387 SHOW_FLAG(THISP_STRING
);
1388 SHOW_FLAG(THISP_NUMBER
);
1389 SHOW_FLAG(THISP_BOOLEAN
);
1390 SHOW_FLAG(EXPR_CLOSURE
);
1391 SHOW_FLAG(INTERPRETED
);
1398 if (!js_Disassemble(cx
, script
, lines
, stdout
))
1400 SrcNotes(cx
, script
);
1401 TryNotes(cx
, script
);
1407 DisassWithSrc(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
1410 #define LINE_BUF_LEN 512
1411 uintN i
, len
, line1
, line2
, bupline
;
1414 char linebuf
[LINE_BUF_LEN
];
1415 jsbytecode
*pc
, *end
;
1416 static char sep
[] = ";-------------------------";
1418 for (i
= 0; i
< argc
; i
++) {
1419 script
= ValueToScript(cx
, argv
[i
]);
1423 if (!script
|| !script
->filename
) {
1424 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1425 JSSMSG_FILE_SCRIPTS_ONLY
);
1429 file
= fopen(script
->filename
, "r");
1431 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1433 script
->filename
, strerror(errno
));
1438 end
= pc
+ script
->length
;
1440 /* burn the leading lines */
1441 line2
= JS_PCToLineNumber(cx
, script
, pc
);
1442 for (line1
= 0; line1
< line2
- 1; line1
++)
1443 fgets(linebuf
, LINE_BUF_LEN
, file
);
1447 line2
= JS_PCToLineNumber(cx
, script
, pc
);
1449 if (line2
< line1
) {
1450 if (bupline
!= line2
) {
1452 fprintf(gOutFile
, "%s %3u: BACKUP\n", sep
, line2
);
1455 if (bupline
&& line1
== line2
)
1456 fprintf(gOutFile
, "%s %3u: RESTORE\n", sep
, line2
);
1458 while (line1
< line2
) {
1459 if (!fgets(linebuf
, LINE_BUF_LEN
, file
)) {
1460 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
,
1461 JSSMSG_UNEXPECTED_EOF
,
1466 fprintf(gOutFile
, "%s %3u: %s", sep
, line1
, linebuf
);
1470 len
= js_Disassemble1(cx
, script
, pc
,
1471 PTRDIFF(pc
, script
->code
, jsbytecode
),
1486 Tracing(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1491 #if JS_THREADED_INTERP
1492 JS_ReportError(cx
, "tracing not supported in JS_THREADED_INTERP builds");
1496 *rval
= BOOLEAN_TO_JSVAL(cx
->tracefp
!= 0);
1500 switch (JS_TypeOfValue(cx
, argv
[0])) {
1502 bval
= JSVAL_IS_INT(argv
[0])
1503 ? JSVAL_TO_INT(argv
[0])
1504 : (jsint
) *JSVAL_TO_DOUBLE(argv
[0]);
1506 case JSTYPE_BOOLEAN
:
1507 bval
= JSVAL_TO_BOOLEAN(argv
[0]);
1510 str
= JS_ValueToString(cx
, argv
[0]);
1513 JS_ReportError(cx
, "tracing: illegal argument %s",
1514 JS_GetStringBytes(str
));
1517 cx
->tracefp
= bval
? stderr
: NULL
;
1523 DumpScope(JSContext
*cx
, JSObject
*obj
, FILE *fp
)
1527 JSScopeProperty
*sprop
;
1532 scope
= OBJ_SCOPE(obj
);
1533 for (sprop
= SCOPE_LAST_PROP(scope
); sprop
; sprop
= sprop
->parent
) {
1534 if (SCOPE_HAD_MIDDLE_DELETE(scope
) && !SCOPE_HAS_PROPERTY(scope
, sprop
))
1536 fprintf(fp
, "%3u %p ", i
, (void *)sprop
);
1538 v
= ID_TO_VALUE(sprop
->id
);
1539 if (JSID_IS_INT(sprop
->id
)) {
1540 fprintf(fp
, "[%ld]", (long)JSVAL_TO_INT(v
));
1542 if (JSID_IS_ATOM(sprop
->id
)) {
1543 str
= JSVAL_TO_STRING(v
);
1545 JS_ASSERT(JSID_IS_OBJECT(sprop
->id
));
1546 str
= js_ValueToString(cx
, v
);
1547 fputs("object ", fp
);
1550 fputs("<error>", fp
);
1552 js_FileEscapedString(fp
, str
, '"');
1554 #define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
1555 DUMP_ATTR(ENUMERATE
);
1556 DUMP_ATTR(READONLY
);
1557 DUMP_ATTR(PERMANENT
);
1558 DUMP_ATTR(EXPORTED
);
1563 fprintf(fp
, " slot %lu flags %x shortid %d\n",
1564 (unsigned long)sprop
->slot
, sprop
->flags
, sprop
->shortid
);
1569 DumpStats(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1579 for (i
= 0; i
< argc
; i
++) {
1580 str
= JS_ValueToString(cx
, argv
[i
]);
1583 argv
[i
] = STRING_TO_JSVAL(str
);
1584 bytes
= JS_GetStringBytes(str
);
1585 if (strcmp(bytes
, "arena") == 0) {
1586 #ifdef JS_ARENAMETER
1587 JS_DumpArenaStats(stdout
);
1589 } else if (strcmp(bytes
, "atom") == 0) {
1590 js_DumpAtoms(cx
, gOutFile
);
1591 } else if (strcmp(bytes
, "global") == 0) {
1592 DumpScope(cx
, cx
->globalObject
, stdout
);
1594 if (!JS_ValueToId(cx
, STRING_TO_JSVAL(str
), &id
))
1596 if (!js_FindProperty(cx
, id
, &obj
, &obj2
, &prop
))
1599 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1600 if (!OBJ_GET_PROPERTY(cx
, obj
, id
, &value
))
1603 if (!prop
|| !JSVAL_IS_OBJECT(value
)) {
1604 fprintf(gErrFile
, "js: invalid stats argument %s\n",
1608 obj
= JSVAL_TO_OBJECT(value
);
1610 DumpScope(cx
, obj
, stdout
);
1617 DumpHeap(JSContext
*cx
, uintN argc
, jsval
*vp
)
1622 uint32 startTraceKind
;
1623 const char *badTraceArg
;
1626 void *thingToIgnore
;
1632 v
= JS_ARGV(cx
, vp
)[0];
1633 if (v
!= JSVAL_NULL
) {
1636 str
= JS_ValueToString(cx
, v
);
1639 JS_ARGV(cx
, vp
)[0] = STRING_TO_JSVAL(str
);
1640 fileName
= JS_GetStringBytes(str
);
1647 v
= JS_ARGV(cx
, vp
)[1];
1648 if (JSVAL_IS_TRACEABLE(v
)) {
1649 startThing
= JSVAL_TO_TRACEABLE(v
);
1650 startTraceKind
= JSVAL_TRACE_KIND(v
);
1651 } else if (v
!= JSVAL_NULL
) {
1652 badTraceArg
= "start";
1653 goto not_traceable_arg
;
1659 v
= JS_ARGV(cx
, vp
)[2];
1660 if (JSVAL_IS_TRACEABLE(v
)) {
1661 thingToFind
= JSVAL_TO_TRACEABLE(v
);
1662 } else if (v
!= JSVAL_NULL
) {
1663 badTraceArg
= "toFind";
1664 goto not_traceable_arg
;
1668 maxDepth
= (size_t)-1;
1670 v
= JS_ARGV(cx
, vp
)[3];
1671 if (v
!= JSVAL_NULL
) {
1674 if (!JS_ValueToECMAUint32(cx
, v
, &depth
))
1680 thingToIgnore
= NULL
;
1682 v
= JS_ARGV(cx
, vp
)[4];
1683 if (JSVAL_IS_TRACEABLE(v
)) {
1684 thingToIgnore
= JSVAL_TO_TRACEABLE(v
);
1685 } else if (v
!= JSVAL_NULL
) {
1686 badTraceArg
= "toIgnore";
1687 goto not_traceable_arg
;
1694 dumpFile
= fopen(fileName
, "w");
1696 JS_ReportError(cx
, "can't open %s: %s", fileName
, strerror(errno
));
1701 ok
= JS_DumpHeap(cx
, dumpFile
, startThing
, startTraceKind
, thingToFind
,
1702 maxDepth
, thingToIgnore
);
1703 if (dumpFile
!= stdout
)
1708 JS_ReportError(cx
, "argument '%s' is not null or a heap-allocated thing",
1717 DoExport(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1726 JS_ReportErrorNumber(cx
, my_GetErrorMessage
, NULL
, JSSMSG_DOEXP_USAGE
);
1729 if (!JS_ValueToObject(cx
, argv
[0], &obj
))
1731 argv
[0] = OBJECT_TO_JSVAL(obj
);
1732 if (!js_ValueToStringId(cx
, argv
[1], &id
))
1734 if (!OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, &obj2
, &prop
))
1737 ok
= OBJ_DEFINE_PROPERTY(cx
, obj
, id
, JSVAL_VOID
, NULL
, NULL
,
1738 JSPROP_EXPORTED
, NULL
);
1740 ok
= OBJ_GET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
1742 attrs
|= JSPROP_EXPORTED
;
1743 ok
= OBJ_SET_ATTRIBUTES(cx
, obj
, id
, prop
, &attrs
);
1745 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
1755 EscapeWideString(jschar
*w
)
1757 static char enuf
[80];
1758 static char hex
[] = "0123456789abcdef";
1765 for (i
= j
= 0; i
< sizeof enuf
- 1; i
++, j
++) {
1769 b
= (unsigned char)(u
>> 8);
1770 c
= (unsigned char)(u
);
1772 if (i
>= sizeof enuf
- 6)
1776 enuf
[i
++] = hex
[b
>> 4];
1777 enuf
[i
++] = hex
[b
& 15];
1778 enuf
[i
++] = hex
[c
>> 4];
1779 enuf
[i
] = hex
[c
& 15];
1780 } else if (!isprint(c
)) {
1781 if (i
>= sizeof enuf
- 4)
1785 enuf
[i
++] = hex
[c
>> 4];
1786 enuf
[i
] = hex
[c
& 15];
1798 ZZ_formatter(JSContext
*cx
, const char *format
, JSBool fromJS
, jsval
**vpp
,
1805 printf("entering ZZ_formatter");
1809 if (!JS_ValueToNumber(cx
, vp
[0], &re
))
1811 if (!JS_ValueToNumber(cx
, vp
[1], &im
))
1813 *va_arg(ap
, jsdouble
*) = re
;
1814 *va_arg(ap
, jsdouble
*) = im
;
1816 re
= va_arg(ap
, jsdouble
);
1817 im
= va_arg(ap
, jsdouble
);
1818 if (!JS_NewNumberValue(cx
, re
, &vp
[0]))
1820 if (!JS_NewNumberValue(cx
, im
, &vp
[1]))
1825 printf("leaving ZZ_formatter");
1830 ConvertArgs(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1832 JSBool b
= JS_FALSE
;
1836 jsdouble d
= 0, I
= 0, re
= 0, im
= 0;
1838 JSString
*str
= NULL
;
1840 JSObject
*obj2
= NULL
;
1841 JSFunction
*fun
= NULL
;
1842 jsval v
= JSVAL_VOID
;
1845 if (!JS_AddArgumentFormatter(cx
, "ZZ", ZZ_formatter
))
1847 ok
= JS_ConvertArguments(cx
, argc
, argv
, "b/ciujdIsSWofvZZ*",
1848 &b
, &c
, &i
, &u
, &j
, &d
, &I
, &s
, &str
, &w
, &obj2
,
1849 &fun
, &v
, &re
, &im
);
1850 JS_RemoveArgumentFormatter(cx
, "ZZ");
1854 "b %u, c %x (%c), i %ld, u %lu, j %ld\n",
1855 b
, c
, (char)c
, i
, u
, j
);
1857 "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n"
1858 "v %s, re %g, im %g\n",
1859 d
, I
, s
, str
? JS_GetStringBytes(str
) : "", EscapeWideString(w
),
1860 JS_GetStringBytes(JS_ValueToString(cx
, OBJECT_TO_JSVAL(obj2
))),
1861 fun
? JS_GetStringBytes(JS_DecompileFunction(cx
, fun
, 4)) : "",
1862 JS_GetStringBytes(JS_ValueToString(cx
, v
)), re
, im
);
1868 BuildDate(JSContext
*cx
, uintN argc
, jsval
*vp
)
1870 char version
[20] = "\n";
1871 #if JS_VERSION < 150
1872 sprintf(version
, " for version %d\n", JS_VERSION
);
1874 fprintf(gOutFile
, "built on %s at %s%s", __DATE__
, __TIME__
, version
);
1880 Clear(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1882 if (argc
!= 0 && !JS_ValueToObject(cx
, argv
[0], &obj
))
1884 JS_ClearScope(cx
, obj
);
1889 Intern(JSContext
*cx
, uintN argc
, jsval
*vp
)
1893 str
= JS_ValueToString(cx
, vp
[2]);
1896 if (!JS_InternUCStringN(cx
, JS_GetStringChars(str
),
1897 JS_GetStringLength(str
))) {
1905 Clone(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1908 JSObject
*funobj
, *parent
, *clone
;
1910 fun
= JS_ValueToFunction(cx
, argv
[0]);
1913 funobj
= JS_GetFunctionObject(fun
);
1915 if (!JS_ValueToObject(cx
, argv
[1], &parent
))
1918 parent
= JS_GetParent(cx
, funobj
);
1920 clone
= JS_CloneFunctionObject(cx
, funobj
, parent
);
1923 *rval
= OBJECT_TO_JSVAL(clone
);
1928 Seal(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1931 JSBool deep
= JS_FALSE
;
1933 if (!JS_ConvertArguments(cx
, argc
, argv
, "o/b", &target
, &deep
))
1937 return JS_SealObject(cx
, target
, deep
);
1941 GetPDA(JSContext
*cx
, uintN argc
, jsval
*vp
)
1943 JSObject
*vobj
, *aobj
, *pdobj
;
1945 JSPropertyDescArray pda
;
1950 if (!JS_ValueToObject(cx
, vp
[2], &vobj
))
1955 aobj
= JS_NewArrayObject(cx
, 0, NULL
);
1958 *vp
= OBJECT_TO_JSVAL(aobj
);
1960 ok
= JS_GetPropertyDescArray(cx
, vobj
, &pda
);
1964 for (i
= 0; i
< pda
.length
; i
++) {
1965 pdobj
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
1971 /* Protect pdobj from GC by setting it as an element of aobj now */
1972 v
= OBJECT_TO_JSVAL(pdobj
);
1973 ok
= JS_SetElement(cx
, aobj
, i
, &v
);
1977 ok
= JS_SetProperty(cx
, pdobj
, "id", &pd
->id
) &&
1978 JS_SetProperty(cx
, pdobj
, "value", &pd
->value
) &&
1979 (v
= INT_TO_JSVAL(pd
->flags
),
1980 JS_SetProperty(cx
, pdobj
, "flags", &v
)) &&
1981 (v
= INT_TO_JSVAL(pd
->slot
),
1982 JS_SetProperty(cx
, pdobj
, "slot", &v
)) &&
1983 JS_SetProperty(cx
, pdobj
, "alias", &pd
->alias
);
1987 JS_PutPropertyDescArray(cx
, &pda
);
1992 GetSLX(JSContext
*cx
, uintN argc
, jsval
*vp
)
1996 script
= ValueToScript(cx
, vp
[2]);
1999 *vp
= INT_TO_JSVAL(js_GetScriptLineExtent(script
));
2004 ToInt32(JSContext
*cx
, uintN argc
, jsval
*vp
)
2008 if (!JS_ValueToInt32(cx
, vp
[2], &i
))
2010 return JS_NewNumberValue(cx
, i
, vp
);
2014 StringsAreUTF8(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
2017 *rval
= JS_CStringsAreUTF8() ? JSVAL_TRUE
: JSVAL_FALSE
;
2022 StackQuota(JSContext
*cx
, uintN argc
, jsval
*vp
)
2027 return JS_NewNumberValue(cx
, (double) gScriptStackQuota
, vp
);
2028 if (!JS_ValueToECMAUint32(cx
, JS_ARGV(cx
, vp
)[0], &n
))
2030 gScriptStackQuota
= n
;
2031 JS_SetScriptStackQuota(cx
, gScriptStackQuota
);
2032 JS_SET_RVAL(cx
, vp
, JSVAL_VOID
);
2036 static const char* badUTF8
= "...\xC0...";
2037 static const char* bigUTF8
= "...\xFB\xBF\xBF\xBF\xBF...";
2038 static const jschar badSurrogate
[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 };
2041 TestUTF8(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2045 size_t charsLength
= 5;
2047 size_t bytesLength
= 20;
2048 if (argc
&& !JS_ValueToInt32(cx
, *argv
, &mode
))
2051 /* The following throw errors if compiled with UTF-8. */
2053 /* mode 1: malformed UTF-8 string. */
2055 JS_NewStringCopyZ(cx
, badUTF8
);
2057 /* mode 2: big UTF-8 character. */
2059 JS_NewStringCopyZ(cx
, bigUTF8
);
2061 /* mode 3: bad surrogate character. */
2063 JS_EncodeCharacters(cx
, badSurrogate
, 6, bytes
, &bytesLength
);
2065 /* mode 4: use a too small buffer. */
2067 JS_DecodeBytes(cx
, "1234567890", 10, chars
, &charsLength
);
2070 JS_ReportError(cx
, "invalid mode parameter");
2073 return !JS_IsExceptionPending (cx
);
2077 ThrowError(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2079 JS_ReportError(cx
, "This is an error");
2083 #define LAZY_STANDARD_CLASSES
2085 /* A class for easily testing the inner/outer object callbacks. */
2086 typedef struct ComplexObject
{
2094 split_create_outer(JSContext
*cx
);
2097 split_create_inner(JSContext
*cx
, JSObject
*outer
);
2099 static ComplexObject
*
2100 split_get_private(JSContext
*cx
, JSObject
*obj
);
2102 JS_STATIC_DLL_CALLBACK(JSBool
)
2103 split_addProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2108 cpx
= split_get_private(cx
, obj
);
2111 if (!cpx
->isInner
&& cpx
->inner
) {
2112 /* Make sure to define this property on the inner object. */
2113 if (!JS_ValueToId(cx
, *vp
, &asId
))
2115 return OBJ_DEFINE_PROPERTY(cx
, cpx
->inner
, asId
, *vp
, NULL
, NULL
,
2116 JSPROP_ENUMERATE
, NULL
);
2121 JS_STATIC_DLL_CALLBACK(JSBool
)
2122 split_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2126 cpx
= split_get_private(cx
, obj
);
2129 if (!cpx
->isInner
&& cpx
->inner
) {
2130 if (JSVAL_IS_STRING(id
)) {
2133 str
= JSVAL_TO_STRING(id
);
2134 return JS_GetUCProperty(cx
, cpx
->inner
, JS_GetStringChars(str
),
2135 JS_GetStringLength(str
), vp
);
2137 if (JSVAL_IS_INT(id
))
2138 return JS_GetElement(cx
, cpx
->inner
, JSVAL_TO_INT(id
), vp
);
2145 JS_STATIC_DLL_CALLBACK(JSBool
)
2146 split_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2150 cpx
= split_get_private(cx
, obj
);
2153 if (!cpx
->isInner
&& cpx
->inner
) {
2154 if (JSVAL_IS_STRING(id
)) {
2157 str
= JSVAL_TO_STRING(id
);
2158 return JS_SetUCProperty(cx
, cpx
->inner
, JS_GetStringChars(str
),
2159 JS_GetStringLength(str
), vp
);
2161 if (JSVAL_IS_INT(id
))
2162 return JS_SetElement(cx
, cpx
->inner
, JSVAL_TO_INT(id
), vp
);
2169 JS_STATIC_DLL_CALLBACK(JSBool
)
2170 split_delProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2175 cpx
= split_get_private(cx
, obj
);
2178 if (!cpx
->isInner
&& cpx
->inner
) {
2179 /* Make sure to define this property on the inner object. */
2180 if (!JS_ValueToId(cx
, *vp
, &asId
))
2182 return OBJ_DELETE_PROPERTY(cx
, cpx
->inner
, asId
, vp
);
2187 JS_STATIC_DLL_CALLBACK(JSBool
)
2188 split_enumerate(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
2189 jsval
*statep
, jsid
*idp
)
2195 case JSENUMERATE_INIT
:
2196 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
2198 if (!cpx
->isInner
&& cpx
->inner
)
2201 iterator
= JS_NewPropertyIterator(cx
, obj
);
2205 *statep
= OBJECT_TO_JSVAL(iterator
);
2210 case JSENUMERATE_NEXT
:
2211 iterator
= (JSObject
*)JSVAL_TO_OBJECT(*statep
);
2212 if (!JS_NextProperty(cx
, iterator
, idp
))
2215 if (!JSVAL_IS_VOID(*idp
))
2219 case JSENUMERATE_DESTROY
:
2220 /* Let GC at our iterator object. */
2221 *statep
= JSVAL_NULL
;
2228 JS_STATIC_DLL_CALLBACK(JSBool
)
2229 split_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
2234 cpx
= split_get_private(cx
, obj
);
2237 if (!cpx
->isInner
&& cpx
->inner
) {
2241 if (!JS_ValueToId(cx
, id
, &asId
))
2244 if (!OBJ_LOOKUP_PROPERTY(cx
, cpx
->inner
, asId
, objp
, &prop
))
2247 OBJ_DROP_PROPERTY(cx
, cpx
->inner
, prop
);
2252 #ifdef LAZY_STANDARD_CLASSES
2253 if (!(flags
& JSRESOLVE_ASSIGNING
)) {
2256 if (!JS_ResolveStandardClass(cx
, obj
, id
, &resolved
))
2266 /* XXX For additional realism, let's resolve some random property here. */
2270 JS_STATIC_DLL_CALLBACK(void)
2271 split_finalize(JSContext
*cx
, JSObject
*obj
)
2273 JS_free(cx
, JS_GetPrivate(cx
, obj
));
2276 JS_STATIC_DLL_CALLBACK(uint32
)
2277 split_mark(JSContext
*cx
, JSObject
*obj
, void *arg
)
2281 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
2283 if (!cpx
->isInner
&& cpx
->inner
) {
2284 /* Mark the inner object. */
2285 JS_MarkGCThing(cx
, cpx
->inner
, "ComplexObject.inner", arg
);
2291 JS_STATIC_DLL_CALLBACK(JSObject
*)
2292 split_outerObject(JSContext
*cx
, JSObject
*obj
)
2296 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
2297 return cpx
->isInner
? cpx
->outer
: obj
;
2300 JS_STATIC_DLL_CALLBACK(JSObject
*)
2301 split_innerObject(JSContext
*cx
, JSObject
*obj
)
2305 cpx
= (ComplexObject
*) JS_GetPrivate(cx
, obj
);
2307 JS_ASSERT(!cpx
->isInner
);
2310 return !cpx
->isInner
? cpx
->inner
: obj
;
2313 static JSExtendedClass split_global_class
= {
2315 JSCLASS_NEW_RESOLVE
| JSCLASS_NEW_ENUMERATE
| JSCLASS_HAS_PRIVATE
|
2316 JSCLASS_IS_EXTENDED
,
2317 split_addProperty
, split_delProperty
,
2318 split_getProperty
, split_setProperty
,
2319 (JSEnumerateOp
)split_enumerate
,
2320 (JSResolveOp
)split_resolve
,
2321 JS_ConvertStub
, split_finalize
,
2322 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2324 NULL
, split_outerObject
, split_innerObject
,
2325 NULL
, NULL
, NULL
, NULL
, NULL
2329 split_create_outer(JSContext
*cx
)
2334 cpx
= (ComplexObject
*) JS_malloc(cx
, sizeof *obj
);
2337 cpx
->isInner
= JS_FALSE
;
2338 cpx
->frozen
= JS_TRUE
;
2342 obj
= JS_NewObject(cx
, &split_global_class
.base
, NULL
, NULL
);
2343 if (!obj
|| !JS_SetParent(cx
, obj
, NULL
)) {
2348 if (!JS_SetPrivate(cx
, obj
, cpx
)) {
2357 split_create_inner(JSContext
*cx
, JSObject
*outer
)
2359 ComplexObject
*cpx
, *outercpx
;
2362 JS_ASSERT(JS_GET_CLASS(cx
, outer
) == &split_global_class
.base
);
2364 cpx
= (ComplexObject
*) JS_malloc(cx
, sizeof *cpx
);
2367 cpx
->isInner
= JS_TRUE
;
2368 cpx
->frozen
= JS_FALSE
;
2372 obj
= JS_NewObject(cx
, &split_global_class
.base
, NULL
, NULL
);
2373 if (!obj
|| !JS_SetParent(cx
, obj
, NULL
) || !JS_SetPrivate(cx
, obj
, cpx
)) {
2378 outercpx
= (ComplexObject
*) JS_GetPrivate(cx
, outer
);
2379 outercpx
->inner
= obj
;
2380 outercpx
->frozen
= JS_FALSE
;
2385 static ComplexObject
*
2386 split_get_private(JSContext
*cx
, JSObject
*obj
)
2389 if (JS_GET_CLASS(cx
, obj
) == &split_global_class
.base
)
2390 return (ComplexObject
*) JS_GetPrivate(cx
, obj
);
2391 obj
= JS_GetParent(cx
, obj
);
2398 sandbox_enumerate(JSContext
*cx
, JSObject
*obj
)
2403 if (!JS_GetProperty(cx
, obj
, "lazy", &v
) || !JS_ValueToBoolean(cx
, v
, &b
))
2405 return !b
|| JS_EnumerateStandardClasses(cx
, obj
);
2409 sandbox_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
2415 if (!JS_GetProperty(cx
, obj
, "lazy", &v
) || !JS_ValueToBoolean(cx
, v
, &b
))
2417 if (b
&& (flags
& JSRESOLVE_ASSIGNING
) == 0) {
2418 if (!JS_ResolveStandardClass(cx
, obj
, id
, &resolved
))
2429 static JSClass sandbox_class
= {
2431 JSCLASS_NEW_RESOLVE
,
2432 JS_PropertyStub
, JS_PropertyStub
,
2433 JS_PropertyStub
, JS_PropertyStub
,
2434 sandbox_enumerate
, (JSResolveOp
)sandbox_resolve
,
2435 JS_ConvertStub
, JS_FinalizeStub
,
2436 JSCLASS_NO_OPTIONAL_MEMBERS
2440 EvalInContext(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
2453 if (!JS_ConvertArguments(cx
, argc
, argv
, "S / o", &str
, &sobj
))
2456 scx
= JS_NewContext(JS_GetRuntime(cx
), gStackChunkSize
);
2458 JS_ReportOutOfMemory(cx
);
2462 #ifdef JS_THREADSAFE
2463 JS_BeginRequest(scx
);
2465 src
= JS_GetStringChars(str
);
2466 srclen
= JS_GetStringLength(str
);
2469 src
[0] == 'l' && src
[1] == 'a' && src
[2] == 'z' && src
[3] == 'y') {
2475 sobj
= JS_NewObject(scx
, &sandbox_class
, NULL
, NULL
);
2476 if (!sobj
|| (!lazy
&& !JS_InitStandardClasses(scx
, sobj
))) {
2480 v
= BOOLEAN_TO_JSVAL(lazy
);
2481 ok
= JS_SetProperty(cx
, sobj
, "lazy", &v
);
2487 *rval
= OBJECT_TO_JSVAL(sobj
);
2490 fp
= JS_GetScriptedCaller(cx
, NULL
);
2491 JS_SetGlobalObject(scx
, sobj
);
2492 JS_ToggleOptions(scx
, JSOPTION_DONT_REPORT_UNCAUGHT
);
2493 ok
= JS_EvaluateUCScript(scx
, sobj
, src
, srclen
,
2494 fp
->script
->filename
,
2495 JS_PCToLineNumber(cx
, fp
->script
,
2499 if (JS_GetPendingException(scx
, &v
))
2500 JS_SetPendingException(cx
, v
);
2502 JS_ReportOutOfMemory(cx
);
2507 #ifdef JS_THREADSAFE
2510 JS_DestroyContext(scx
);
2514 #ifdef JS_THREADSAFE
2517 Sleep(JSContext
*cx
, uintN argc
, jsval
*vp
)
2523 if (!JS_ConvertArguments(cx
, argc
, JS_ARGV(cx
, vp
), "d", &t_secs
))
2526 if (t_secs
< 0 || JSDOUBLE_IS_NaN(t_secs
))
2529 rc
= JS_SuspendRequest(cx
);
2530 t_ticks
= (PRUint32
)(PR_TicksPerSecond() * t_secs
);
2531 if (PR_Sleep(t_ticks
) == PR_SUCCESS
)
2535 JS_ResumeRequest(cx
, rc
);
2539 typedef struct ScatterThreadData ScatterThreadData
;
2540 typedef struct ScatterData ScatterData
;
2542 typedef enum ScatterStatus
{
2548 struct ScatterData
{
2549 ScatterThreadData
*threads
;
2553 ScatterStatus status
;
2556 struct ScatterThreadData
{
2558 ScatterData
*shared
;
2565 DoScatteredWork(JSContext
*cx
, ScatterThreadData
*td
)
2567 jsval
*rval
= &td
->shared
->results
[td
->index
];
2569 if (!JS_CallFunctionValue(cx
, NULL
, td
->fn
, 0, NULL
, rval
)) {
2571 JS_GetPendingException(cx
, rval
);
2572 JS_ClearPendingException(cx
);
2577 RunScatterThread(void *arg
)
2579 ScatterThreadData
*td
;
2583 td
= (ScatterThreadData
*)arg
;
2586 /* Wait for go signal. */
2587 PR_Lock(td
->shared
->lock
);
2588 while ((st
= td
->shared
->status
) == SCATTER_WAIT
)
2589 PR_WaitCondVar(td
->shared
->cvar
, PR_INTERVAL_NO_TIMEOUT
);
2590 PR_Unlock(td
->shared
->lock
);
2592 if (st
== SCATTER_CANCEL
)
2596 JS_SetContextThread(cx
);
2597 JS_SetThreadStackLimit(cx
, 0);
2598 JS_BeginRequest(cx
);
2599 DoScatteredWork(cx
, td
);
2601 JS_ClearContextThread(cx
);
2605 * scatter(fnArray) - Call each function in `fnArray` without arguments, each
2606 * in a different thread. When all threads have finished, return an array: the
2607 * return values. Errors are not propagated; if any of the function calls
2608 * fails, the corresponding element in the results array gets the exception
2609 * object, if any, else (undefined).
2612 Scatter(JSContext
*cx
, uintN argc
, jsval
*vp
)
2615 jsuint n
; /* number of threads */
2622 if (!gEnableBranchCallback
) {
2623 /* Enable the branch callback, for periodic scope-sharing. */
2624 gEnableBranchCallback
= JS_TRUE
;
2625 JS_SetBranchCallback(cx
, my_BranchCallback
);
2626 JS_ToggleOptions(cx
, JSOPTION_NATIVE_BRANCH_CALLBACK
);
2633 sd
.status
= SCATTER_WAIT
;
2635 if (JSVAL_IS_PRIMITIVE(JS_ARGV(cx
, vp
)[0]))
2638 inArr
= JSVAL_TO_OBJECT(JS_ARGV(cx
, vp
)[0]);
2639 ok
= JS_GetArrayLength(cx
, inArr
, &n
);
2645 sd
.lock
= PR_NewLock();
2649 sd
.cvar
= PR_NewCondVar(sd
.lock
);
2653 sd
.results
= (jsval
*) malloc(n
* sizeof(jsval
));
2656 for (i
= 0; i
< n
; i
++) {
2657 sd
.results
[i
] = JSVAL_VOID
;
2658 ok
= JS_AddRoot(cx
, &sd
.results
[i
]);
2661 JS_RemoveRoot(cx
, &sd
.results
[i
]);
2668 sd
.threads
= (ScatterThreadData
*) malloc(n
* sizeof(ScatterThreadData
));
2671 for (i
= 0; i
< n
; i
++) {
2672 sd
.threads
[i
].index
= i
;
2673 sd
.threads
[i
].shared
= &sd
;
2674 sd
.threads
[i
].thr
= NULL
;
2675 sd
.threads
[i
].cx
= NULL
;
2676 sd
.threads
[i
].fn
= JSVAL_NULL
;
2678 ok
= JS_AddRoot(cx
, &sd
.threads
[i
].fn
);
2679 if (ok
&& !JS_GetElement(cx
, inArr
, (jsint
) i
, &sd
.threads
[i
].fn
)) {
2680 JS_RemoveRoot(cx
, &sd
.threads
[i
].fn
);
2685 JS_RemoveRoot(cx
, &sd
.threads
[i
].fn
);
2692 for (i
= 1; i
< n
; i
++) {
2693 JSContext
*newcx
= JS_NewContext(JS_GetRuntime(cx
), 8192);
2696 JS_SetGlobalObject(newcx
, JS_GetGlobalObject(cx
));
2697 JS_ClearContextThread(newcx
);
2698 sd
.threads
[i
].cx
= newcx
;
2701 for (i
= 1; i
< n
; i
++) {
2702 PRThread
*t
= PR_CreateThread(PR_USER_THREAD
,
2710 /* Failed to start thread. */
2712 sd
.status
= SCATTER_CANCEL
;
2713 PR_NotifyAllCondVar(sd
.cvar
);
2716 PR_JoinThread(sd
.threads
[i
].thr
);
2720 sd
.threads
[i
].thr
= t
;
2723 sd
.status
= SCATTER_GO
;
2724 PR_NotifyAllCondVar(sd
.cvar
);
2727 DoScatteredWork(cx
, &sd
.threads
[0]);
2729 rc
= JS_SuspendRequest(cx
);
2730 for (i
= 1; i
< n
; i
++) {
2731 PR_JoinThread(sd
.threads
[i
].thr
);
2733 JS_ResumeRequest(cx
, rc
);
2736 arr
= JS_NewArrayObject(cx
, n
, sd
.results
);
2739 *vp
= OBJECT_TO_JSVAL(arr
);
2746 for (i
= 0; i
< n
; i
++) {
2747 JS_RemoveRoot(cx
, &sd
.threads
[i
].fn
);
2748 acx
= sd
.threads
[i
].cx
;
2750 JS_SetContextThread(acx
);
2751 JS_DestroyContext(acx
);
2757 for (i
= 0; i
< n
; i
++)
2758 JS_RemoveRoot(cx
, &sd
.results
[i
]);
2762 PR_DestroyCondVar(sd
.cvar
);
2764 PR_DestroyLock(sd
.lock
);
2775 /* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
2776 static JSFunctionSpec shell_functions
[] = {
2777 JS_FS("version", Version
, 0,0,0),
2778 JS_FS("options", Options
, 0,0,0),
2779 JS_FS("load", Load
, 1,0,0),
2780 JS_FN("readline", ReadLine
, 0,0,0),
2781 JS_FS("print", Print
, 0,0,0),
2782 JS_FS("help", Help
, 0,0,0),
2783 JS_FS("quit", Quit
, 0,0,0),
2784 JS_FN("gc", GC
, 0,0,0),
2785 JS_FN("gcparam", GCParameter
, 2,2,0),
2786 JS_FN("countHeap", CountHeap
, 0,0,0),
2788 JS_FN("gczeal", GCZeal
, 1,1,0),
2790 JS_FS("trap", Trap
, 3,0,0),
2791 JS_FS("untrap", Untrap
, 2,0,0),
2792 JS_FS("line2pc", LineToPC
, 0,0,0),
2793 JS_FS("pc2line", PCToLine
, 0,0,0),
2794 JS_FN("stackQuota", StackQuota
, 0,0,0),
2795 JS_FS("stringsAreUTF8", StringsAreUTF8
, 0,0,0),
2796 JS_FS("testUTF8", TestUTF8
, 1,0,0),
2797 JS_FS("throwError", ThrowError
, 0,0,0),
2799 JS_FS("dis", Disassemble
, 1,0,0),
2800 JS_FS("dissrc", DisassWithSrc
, 1,0,0),
2801 JS_FN("dumpHeap", DumpHeap
, 0,0,0),
2802 JS_FS("notes", Notes
, 1,0,0),
2803 JS_FS("tracing", Tracing
, 0,0,0),
2804 JS_FS("stats", DumpStats
, 1,0,0),
2807 JS_FS("xport", DoExport
, 2,0,0),
2810 JS_FS("cvtargs", ConvertArgs
, 0,0,12),
2812 JS_FN("build", BuildDate
, 0,0,0),
2813 JS_FS("clear", Clear
, 0,0,0),
2814 JS_FN("intern", Intern
, 1,1,0),
2815 JS_FS("clone", Clone
, 1,0,0),
2816 JS_FS("seal", Seal
, 1,0,1),
2817 JS_FN("getpda", GetPDA
, 1,1,0),
2818 JS_FN("getslx", GetSLX
, 1,1,0),
2819 JS_FN("toint32", ToInt32
, 1,1,0),
2820 JS_FS("evalcx", EvalInContext
, 1,0,0),
2822 JS_FS("startShark", js_StartShark
, 0,0,0),
2823 JS_FS("stopShark", js_StopShark
, 0,0,0),
2824 JS_FS("connectShark", js_ConnectShark
, 0,0,0),
2825 JS_FS("disconnectShark", js_DisconnectShark
, 0,0,0),
2828 JS_FS("arrayInfo", js_ArrayInfo
, 1,0,0),
2830 #ifdef JS_THREADSAFE
2831 JS_FN("sleep", Sleep
, 1,1,0),
2832 JS_FN("scatter", Scatter
, 1,1,0),
2837 static const char shell_help_header
[] =
2838 "Command Description\n"
2839 "======= ===========\n";
2841 static const char *const shell_help_messages
[] = {
2842 "version([number]) Get or set JavaScript version number",
2843 "options([option ...]) Get or toggle JavaScript options",
2844 "load(['foo.js' ...]) Load files named by string arguments",
2845 "readline() Read a single line from stdin",
2846 "print([exp ...]) Evaluate and print expressions",
2847 "help([name ...]) Display usage and help messages",
2848 "quit() Quit the shell",
2849 "gc() Run the garbage collector",
2850 "gcparam(name, value)\n"
2851 " Wrapper for JS_SetGCParameter. The name must be either 'maxBytes' or\n"
2852 " 'maxMallocBytes' and the value must be convertable to a positive uint32",
2853 "countHeap([start[, kind]])\n"
2854 " Count the number of live GC things in the heap or things reachable from\n"
2855 " start when it is given and is not null. kind is either 'all' (default) to\n"
2856 " count all things or one of 'object', 'double', 'string', 'function',\n"
2857 " 'qname', 'namespace', 'xml' to count only things of that kind",
2859 "gczeal(level) How zealous the garbage collector should be",
2861 "trap([fun, [pc,]] exp) Trap bytecode execution",
2862 "untrap(fun[, pc]) Remove a trap",
2863 "line2pc([fun,] line) Map line number to PC",
2864 "pc2line(fun[, pc]) Map PC to line number",
2865 "stackQuota([number]) Query/set script stack quota",
2866 "stringsAreUTF8() Check if strings are UTF-8 encoded",
2867 "testUTF8(mode) Perform UTF-8 tests (modes are 1 to 4)",
2868 "throwError() Throw an error from JS_ReportError",
2870 "dis([fun]) Disassemble functions into bytecodes",
2871 "dissrc([fun]) Disassemble functions with source lines",
2872 "dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])\n"
2873 " Interface to JS_DumpHeap with output sent to file",
2874 "notes([fun]) Show source notes for functions",
2875 "tracing([toggle]) Turn tracing on or off",
2876 "stats([string ...]) Dump 'arena', 'atom', 'global' stats",
2879 "xport(obj, property) Export the given property of obj",
2882 "cvtargs(arg1..., arg12) Test argument formater",
2884 "build() Show build date and time",
2885 "clear([obj]) Clear properties of object",
2886 "intern(str) Internalize str in the atom table",
2887 "clone(fun[, scope]) Clone function object",
2888 "seal(obj[, deep]) Seal object, or object graph if deep",
2889 "getpda(obj) Get the property descriptors for obj",
2890 "getslx(obj) Get script line extent",
2891 "toint32(n) Testing hook for JS_ValueToInt32",
2893 " Evaluate s in optional sandbox object o\n"
2894 " if (s == '' && !o) return new o with eager standard classes\n"
2895 " if (s == 'lazy' && !o) return new o with lazy standard classes",
2897 "startShark() Start a Shark session.\n"
2898 " Shark must be running with programatic sampling.",
2899 "stopShark() Stop a running Shark session.",
2900 "connectShark() Connect to Shark.\n"
2901 " The -k switch does this automatically.",
2902 "disconnectShark() Disconnect from Shark.",
2905 "arrayInfo(a1, a2, ...) Report statistics about arrays.",
2907 #ifdef JS_THREADSAFE
2908 "sleep(dt) Sleep for dt seconds",
2909 "scatter(fns) Call functions concurrently (ignoring errors)",
2913 /* Help messages must match shell functions. */
2914 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages
) + 1 ==
2915 JS_ARRAY_LENGTH(shell_functions
));
2921 const char *const *m
;
2924 /* Each message must begin with "function_name(" prefix. */
2925 for (m
= shell_help_messages
; m
!= JS_ARRAY_END(shell_help_messages
); ++m
) {
2926 lp
= strchr(*m
, '(');
2928 JS_ASSERT(memcmp(shell_functions
[m
- shell_help_messages
].name
,
2933 # define CheckHelpMessages() ((void) 0)
2937 Help(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2940 int did_header
, did_something
;
2946 fprintf(gOutFile
, "%s\n", JS_GetImplementationVersion());
2948 fputs(shell_help_header
, gOutFile
);
2949 for (i
= 0; shell_functions
[i
].name
; i
++)
2950 fprintf(gOutFile
, "%s\n", shell_help_messages
[i
]);
2953 for (i
= 0; i
< argc
; i
++) {
2955 type
= JS_TypeOfValue(cx
, argv
[i
]);
2956 if (type
== JSTYPE_FUNCTION
) {
2957 fun
= JS_ValueToFunction(cx
, argv
[i
]);
2958 str
= fun
->atom
? ATOM_TO_STRING(fun
->atom
) : NULL
;
2959 } else if (type
== JSTYPE_STRING
) {
2960 str
= JSVAL_TO_STRING(argv
[i
]);
2965 bytes
= JS_GetStringBytes(str
);
2966 for (j
= 0; shell_functions
[j
].name
; j
++) {
2967 if (!strcmp(bytes
, shell_functions
[j
].name
)) {
2970 fputs(shell_help_header
, gOutFile
);
2973 fprintf(gOutFile
, "%s\n", shell_help_messages
[j
]);
2978 if (!did_something
) {
2979 str
= JS_ValueToString(cx
, argv
[i
]);
2982 fprintf(gErrFile
, "Sorry, no help for %s\n",
2983 JS_GetStringBytes(str
));
2991 split_setup(JSContext
*cx
)
2993 JSObject
*outer
, *inner
, *arguments
;
2995 outer
= split_create_outer(cx
);
2998 JS_SetGlobalObject(cx
, outer
);
3000 inner
= split_create_inner(cx
, outer
);
3004 if (!JS_DefineFunctions(cx
, inner
, shell_functions
))
3006 JS_ClearScope(cx
, outer
);
3008 /* Create a dummy arguments object. */
3009 arguments
= JS_NewArrayObject(cx
, 0, NULL
);
3011 !JS_DefineProperty(cx
, inner
, "arguments", OBJECT_TO_JSVAL(arguments
),
3016 #ifndef LAZY_STANDARD_CLASSES
3017 if (!JS_InitStandardClasses(cx
, inner
))
3025 * Define a JS object called "it". Give it class operations that printf why
3026 * they're being called for tutorial purposes.
3029 ITS_COLOR
, ITS_HEIGHT
, ITS_WIDTH
, ITS_FUNNY
, ITS_ARRAY
, ITS_RDONLY
3032 static JSPropertySpec its_props
[] = {
3033 {"color", ITS_COLOR
, JSPROP_ENUMERATE
, NULL
, NULL
},
3034 {"height", ITS_HEIGHT
, JSPROP_ENUMERATE
, NULL
, NULL
},
3035 {"width", ITS_WIDTH
, JSPROP_ENUMERATE
, NULL
, NULL
},
3036 {"funny", ITS_FUNNY
, JSPROP_ENUMERATE
, NULL
, NULL
},
3037 {"array", ITS_ARRAY
, JSPROP_ENUMERATE
, NULL
, NULL
},
3038 {"rdonly", ITS_RDONLY
, JSPROP_READONLY
, NULL
, NULL
},
3039 {NULL
,0,0,NULL
,NULL
}
3043 its_item(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
3045 *rval
= OBJECT_TO_JSVAL(obj
);
3047 JS_SetCallReturnValue2(cx
, argv
[0]);
3052 its_bindMethod(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
3058 if (!JS_ConvertArguments(cx
, argc
, argv
, "so", &name
, &method
))
3061 *rval
= OBJECT_TO_JSVAL(method
);
3063 if (JS_TypeOfValue(cx
, *rval
) != JSTYPE_FUNCTION
) {
3064 JSString
*valstr
= JS_ValueToString(cx
, *rval
);
3066 JS_ReportError(cx
, "can't bind method %s to non-callable object %s",
3067 name
, JS_GetStringBytes(valstr
));
3072 if (!JS_DefineProperty(cx
, obj
, name
, *rval
, NULL
, NULL
, JSPROP_ENUMERATE
))
3075 return JS_SetParent(cx
, method
, obj
);
3078 static JSFunctionSpec its_methods
[] = {
3079 {"item", its_item
, 0,0,0},
3080 {"bindMethod", its_bindMethod
, 2,0,0},
3084 #ifdef JSD_LOWLEVEL_SOURCE
3086 * This facilitates sending source to JSD (the debugger system) in the shell
3087 * where the source is loaded using the JSFILE hack in jsscan. The function
3088 * below is used as a callback for the jsdbgapi JS_SetSourceHandler hook.
3089 * A more normal embedding (e.g. mozilla) loads source itself and can send
3090 * source directly to JSD without using this hook scheme.
3093 SendSourceToJSDebugger(const char *filename
, uintN lineno
,
3094 jschar
*str
, size_t length
,
3095 void **listenerTSData
, JSDContext
* jsdc
)
3097 JSDSourceText
*jsdsrc
= (JSDSourceText
*) *listenerTSData
;
3101 filename
= "typein";
3103 jsdsrc
= JSD_NewSourceText(jsdc
, filename
);
3105 jsdsrc
= JSD_FindSourceForURL(jsdc
, filename
);
3106 if (jsdsrc
&& JSD_SOURCE_PARTIAL
!=
3107 JSD_GetSourceStatus(jsdc
, jsdsrc
)) {
3113 jsdsrc
= JSD_AppendUCSourceText(jsdc
,jsdsrc
, str
, length
,
3114 JSD_SOURCE_PARTIAL
);
3116 *listenerTSData
= jsdsrc
;
3118 #endif /* JSD_LOWLEVEL_SOURCE */
3120 static JSBool its_noisy
; /* whether to be noisy when finalizing it */
3121 static JSBool its_enum_fail
;/* whether to fail when enumerating it */
3124 its_addProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
3127 fprintf(gOutFile
, "adding its property %s,",
3128 JS_GetStringBytes(JS_ValueToString(cx
, id
)));
3129 fprintf(gOutFile
, " initial value %s\n",
3130 JS_GetStringBytes(JS_ValueToString(cx
, *vp
)));
3136 its_delProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
3139 fprintf(gOutFile
, "deleting its property %s,",
3140 JS_GetStringBytes(JS_ValueToString(cx
, id
)));
3141 fprintf(gOutFile
, " current value %s\n",
3142 JS_GetStringBytes(JS_ValueToString(cx
, *vp
)));
3148 its_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
3151 fprintf(gOutFile
, "getting its property %s,",
3152 JS_GetStringBytes(JS_ValueToString(cx
, id
)));
3153 fprintf(gOutFile
, " current value %s\n",
3154 JS_GetStringBytes(JS_ValueToString(cx
, *vp
)));
3160 its_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
3164 fprintf(gOutFile
, "setting its property %s,",
3165 JS_GetStringBytes(JS_ValueToString(cx
, id
)));
3166 fprintf(gOutFile
, " new value %s\n",
3167 JS_GetStringBytes(JS_ValueToString(cx
, *vp
)));
3170 if (!JSVAL_IS_STRING(id
))
3173 str
= JS_GetStringBytes(JSVAL_TO_STRING(id
));
3174 if (!strcmp(str
, "noisy"))
3175 return JS_ValueToBoolean(cx
, *vp
, &its_noisy
);
3176 else if (!strcmp(str
, "enum_fail"))
3177 return JS_ValueToBoolean(cx
, *vp
, &its_enum_fail
);
3183 * Its enumerator, implemented using the "new" enumerate API,
3187 its_enumerate(JSContext
*cx
, JSObject
*obj
, JSIterateOp enum_op
,
3188 jsval
*statep
, jsid
*idp
)
3193 case JSENUMERATE_INIT
:
3195 fprintf(gOutFile
, "enumerate its properties\n");
3197 iterator
= JS_NewPropertyIterator(cx
, obj
);
3201 *statep
= OBJECT_TO_JSVAL(iterator
);
3206 case JSENUMERATE_NEXT
:
3207 if (its_enum_fail
) {
3208 JS_ReportError(cx
, "its enumeration failed");
3212 iterator
= (JSObject
*) JSVAL_TO_OBJECT(*statep
);
3213 if (!JS_NextProperty(cx
, iterator
, idp
))
3216 if (!JSVAL_IS_VOID(*idp
))
3220 case JSENUMERATE_DESTROY
:
3221 /* Allow our iterator object to be GC'd. */
3222 *statep
= JSVAL_NULL
;
3230 its_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
3234 fprintf(gOutFile
, "resolving its property %s, flags {%s,%s,%s}\n",
3235 JS_GetStringBytes(JS_ValueToString(cx
, id
)),
3236 (flags
& JSRESOLVE_QUALIFIED
) ? "qualified" : "",
3237 (flags
& JSRESOLVE_ASSIGNING
) ? "assigning" : "",
3238 (flags
& JSRESOLVE_DETECTING
) ? "detecting" : "");
3244 its_convert(JSContext
*cx
, JSObject
*obj
, JSType type
, jsval
*vp
)
3247 fprintf(gOutFile
, "converting it to %s type\n", JS_GetTypeName(cx
, type
));
3252 its_finalize(JSContext
*cx
, JSObject
*obj
)
3255 fprintf(gOutFile
, "finalizing it\n");
3258 static JSClass its_class
= {
3259 "It", JSCLASS_NEW_RESOLVE
| JSCLASS_NEW_ENUMERATE
,
3260 its_addProperty
, its_delProperty
, its_getProperty
, its_setProperty
,
3261 (JSEnumerateOp
)its_enumerate
, (JSResolveOp
)its_resolve
,
3262 its_convert
, its_finalize
,
3263 JSCLASS_NO_OPTIONAL_MEMBERS
3266 JSErrorFormatString jsShell_ErrorFormatString
[JSErr_Limit
] = {
3267 #define MSG_DEF(name, number, count, exception, format) \
3268 { format, count, JSEXN_ERR } ,
3269 #include "jsshell.msg"
3273 static const JSErrorFormatString
*
3274 my_GetErrorMessage(void *userRef
, const char *locale
, const uintN errorNumber
)
3276 if ((errorNumber
> 0) && (errorNumber
< JSShellErr_Limit
))
3277 return &jsShell_ErrorFormatString
[errorNumber
];
3282 my_ErrorReporter(JSContext
*cx
, const char *message
, JSErrorReport
*report
)
3289 fprintf(gErrFile
, "%s\n", message
);
3293 /* Conditionally ignore reported warnings. */
3294 if (JSREPORT_IS_WARNING(report
->flags
) && !reportWarnings
)
3298 if (report
->filename
)
3299 prefix
= JS_smprintf("%s:", report
->filename
);
3300 if (report
->lineno
) {
3302 prefix
= JS_smprintf("%s%u: ", tmp
? tmp
: "", report
->lineno
);
3305 if (JSREPORT_IS_WARNING(report
->flags
)) {
3307 prefix
= JS_smprintf("%s%swarning: ",
3309 JSREPORT_IS_STRICT(report
->flags
) ? "strict " : "");
3313 /* embedded newlines -- argh! */
3314 while ((ctmp
= strchr(message
, '\n')) != 0) {
3317 fputs(prefix
, gErrFile
);
3318 fwrite(message
, 1, ctmp
- message
, gErrFile
);
3322 /* If there were no filename or lineno, the prefix might be empty */
3324 fputs(prefix
, gErrFile
);
3325 fputs(message
, gErrFile
);
3327 if (!report
->linebuf
) {
3328 fputc('\n', gErrFile
);
3332 /* report->linebuf usually ends with a newline. */
3333 n
= strlen(report
->linebuf
);
3334 fprintf(gErrFile
, ":\n%s%s%s%s",
3337 (n
> 0 && report
->linebuf
[n
-1] == '\n') ? "" : "\n",
3339 n
= PTRDIFF(report
->tokenptr
, report
->linebuf
, char);
3340 for (i
= j
= 0; i
< n
; i
++) {
3341 if (report
->linebuf
[i
] == '\t') {
3342 for (k
= (j
+ 8) & ~7; j
< k
; j
++) {
3343 fputc('.', gErrFile
);
3347 fputc('.', gErrFile
);
3350 fputs("^\n", gErrFile
);
3352 if (!JSREPORT_IS_WARNING(report
->flags
)) {
3353 if (report
->errorNumber
== JSMSG_OUT_OF_MEMORY
) {
3354 gExitCode
= EXITCODE_OUT_OF_MEMORY
;
3356 gExitCode
= EXITCODE_RUNTIME_ERROR
;
3359 JS_free(cx
, prefix
);
3362 #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
3364 Exec(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
3367 const char *name
, **nargv
;
3373 fun
= JS_ValueToFunction(cx
, argv
[-2]);
3378 name
= JS_GetStringBytes(ATOM_TO_STRING(fun
->atom
));
3380 nargv
= JS_malloc(cx
, (nargc
+ 1) * sizeof(char *));
3384 for (i
= 1; i
< nargc
; i
++) {
3385 str
= JS_ValueToString(cx
, argv
[i
-1]);
3390 nargv
[i
] = JS_GetStringBytes(str
);
3399 (void) execvp(name
, (char **)nargv
);
3403 while (waitpid(pid
, &status
, 0) < 0 && errno
== EINTR
)
3413 global_enumerate(JSContext
*cx
, JSObject
*obj
)
3415 #ifdef LAZY_STANDARD_CLASSES
3416 return JS_EnumerateStandardClasses(cx
, obj
);
3423 global_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
3426 #ifdef LAZY_STANDARD_CLASSES
3427 if ((flags
& JSRESOLVE_ASSIGNING
) == 0) {
3430 if (!JS_ResolveStandardClass(cx
, obj
, id
, &resolved
))
3439 #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
3440 if ((flags
& (JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
)) == 0) {
3442 * Do this expensive hack only for unoptimized Unix builds, which are
3443 * not used for benchmarking.
3445 char *path
, *comp
, *full
;
3450 if (!JSVAL_IS_STRING(id
))
3452 path
= getenv("PATH");
3455 path
= JS_strdup(cx
, path
);
3458 name
= JS_GetStringBytes(JSVAL_TO_STRING(id
));
3460 for (comp
= strtok(path
, ":"); comp
; comp
= strtok(NULL
, ":")) {
3461 if (*comp
!= '\0') {
3462 full
= JS_smprintf("%s/%s", comp
, name
);
3464 JS_ReportOutOfMemory(cx
);
3469 full
= (char *)name
;
3471 found
= (access(full
, X_OK
) == 0);
3475 fun
= JS_DefineFunction(cx
, obj
, name
, Exec
, 0,
3491 JSClass global_class
= {
3492 "global", JSCLASS_NEW_RESOLVE
| JSCLASS_GLOBAL_FLAGS
,
3493 JS_PropertyStub
, JS_PropertyStub
,
3494 JS_PropertyStub
, JS_PropertyStub
,
3495 global_enumerate
, (JSResolveOp
) global_resolve
,
3496 JS_ConvertStub
, JS_FinalizeStub
,
3497 JSCLASS_NO_OPTIONAL_MEMBERS
3501 env_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
3503 /* XXX porting may be easy, but these don't seem to supply setenv by default */
3504 #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS
3505 JSString
*idstr
, *valstr
;
3506 const char *name
, *value
;
3509 idstr
= JS_ValueToString(cx
, id
);
3510 valstr
= JS_ValueToString(cx
, *vp
);
3511 if (!idstr
|| !valstr
)
3513 name
= JS_GetStringBytes(idstr
);
3514 value
= JS_GetStringBytes(valstr
);
3515 #if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX
3517 char *waste
= JS_smprintf("%s=%s", name
, value
);
3519 JS_ReportOutOfMemory(cx
);
3525 * HPUX9 at least still has the bad old non-copying putenv.
3527 * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
3528 * that will crash if you pass it an auto char array (so it must place
3529 * its argument directly in the char *environ[] array).
3535 rv
= setenv(name
, value
, 1);
3538 JS_ReportError(cx
, "can't set envariable %s to %s", name
, value
);
3541 *vp
= STRING_TO_JSVAL(valstr
);
3542 #endif /* !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS */
3547 env_enumerate(JSContext
*cx
, JSObject
*obj
)
3549 static JSBool reflected
;
3550 char **evp
, *name
, *value
;
3557 for (evp
= (char **)JS_GetPrivate(cx
, obj
); (name
= *evp
) != NULL
; evp
++) {
3558 value
= strchr(name
, '=');
3562 valstr
= JS_NewStringCopyZ(cx
, value
);
3566 ok
= JS_DefineProperty(cx
, obj
, name
, STRING_TO_JSVAL(valstr
),
3567 NULL
, NULL
, JSPROP_ENUMERATE
);
3574 reflected
= JS_TRUE
;
3579 env_resolve(JSContext
*cx
, JSObject
*obj
, jsval id
, uintN flags
,
3582 JSString
*idstr
, *valstr
;
3583 const char *name
, *value
;
3585 if (flags
& JSRESOLVE_ASSIGNING
)
3588 idstr
= JS_ValueToString(cx
, id
);
3591 name
= JS_GetStringBytes(idstr
);
3592 value
= getenv(name
);
3594 valstr
= JS_NewStringCopyZ(cx
, value
);
3597 if (!JS_DefineProperty(cx
, obj
, name
, STRING_TO_JSVAL(valstr
),
3598 NULL
, NULL
, JSPROP_ENUMERATE
)) {
3606 static JSClass env_class
= {
3607 "environment", JSCLASS_HAS_PRIVATE
| JSCLASS_NEW_RESOLVE
,
3608 JS_PropertyStub
, JS_PropertyStub
,
3609 JS_PropertyStub
, env_setProperty
,
3610 env_enumerate
, (JSResolveOp
) env_resolve
,
3611 JS_ConvertStub
, JS_FinalizeStub
,
3612 JSCLASS_NO_OPTIONAL_MEMBERS
3618 defineProperty(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
3623 JSBool dontDelete
, readOnly
, dontEnum
;
3624 const jschar
*chars
;
3628 dontDelete
= readOnly
= dontEnum
= JS_FALSE
;
3629 if (!JS_ConvertArguments(cx
, argc
, argv
, "Sv/bbb",
3630 &str
, &value
, &dontDelete
, &readOnly
, &dontEnum
)) {
3633 chars
= JS_GetStringChars(str
);
3634 length
= JS_GetStringLength(str
);
3635 attrs
= dontEnum
? 0 : JSPROP_ENUMERATE
;
3637 attrs
|= JSPROP_PERMANENT
;
3639 attrs
|= JSPROP_READONLY
;
3640 return JS_DefineUCProperty(cx
, obj
, chars
, length
, value
, NULL
, NULL
,
3645 Evaluate(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
3647 /* function evaluate(source, filename, lineno) { ... } */
3649 const char *filename
= "";
3659 if (!JS_ConvertArguments(cx
, argc
, argv
, "S/su",
3660 &source
, &filename
, &lineno
)) {
3664 oldopts
= JS_GetOptions(cx
);
3665 JS_SetOptions(cx
, oldopts
| JSOPTION_COMPILE_N_GO
);
3666 ok
= JS_EvaluateUCScript(cx
, obj
, JS_GetStringChars(source
),
3667 JS_GetStringLength(source
), filename
,
3669 JS_SetOptions(cx
, oldopts
);
3675 #include <sys/stat.h>
3678 * Returns a JS_malloc'd string (that the caller needs to JS_free)
3679 * containing the directory (non-leaf) part of |from| prepended to |leaf|.
3680 * If |from| is empty or a leaf, MakeAbsolutePathname returns a copy of leaf.
3681 * Returns NULL to indicate an error.
3684 MakeAbsolutePathname(JSContext
*cx
, const char *from
, const char *leaf
)
3688 const char *slash
= NULL
, *cp
;
3704 /* We were given a leaf or |from| was empty. */
3705 return JS_strdup(cx
, leaf
);
3708 /* Else, we were given a real pathname, return that + the leaf. */
3709 dirlen
= slash
- from
+ 1;
3710 dir
= JS_malloc(cx
, dirlen
+ strlen(leaf
) + 1);
3714 strncpy(dir
, from
, dirlen
);
3715 strcpy(dir
+ dirlen
, leaf
); /* Note: we can't use strcat here. */
3721 snarf(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
3724 const char *filename
;
3732 str
= JS_ValueToString(cx
, argv
[0]);
3735 filename
= JS_GetStringBytes(str
);
3737 /* Get the currently executing script's name. */
3738 fp
= JS_GetScriptedCaller(cx
, NULL
);
3739 JS_ASSERT(fp
&& fp
->script
->filename
);
3740 pathname
= MakeAbsolutePathname(cx
, fp
->script
->filename
, filename
);
3747 file
= fopen(pathname
, "rb");
3749 JS_ReportError(cx
, "can't open %s: %s", pathname
, strerror(errno
));
3751 if (fseek(file
, 0, SEEK_END
) == EOF
) {
3752 JS_ReportError(cx
, "can't seek end of %s", pathname
);
3755 if (len
== -1 || fseek(file
, 0, SEEK_SET
) == EOF
) {
3756 JS_ReportError(cx
, "can't seek start of %s", pathname
);
3758 buf
= JS_malloc(cx
, len
+ 1);
3760 cc
= fread(buf
, 1, len
, file
);
3763 JS_ReportError(cx
, "can't read %s: %s", pathname
,
3764 (cc
< 0) ? strerror(errno
)
3775 JS_free(cx
, pathname
);
3782 str
= JS_NewString(cx
, buf
, len
);
3787 *rval
= STRING_TO_JSVAL(str
);
3791 #endif /* NARCISSUS */
3794 ContextCallback(JSContext
*cx
, uintN contextOp
)
3796 if (contextOp
== JSCONTEXT_NEW
) {
3797 JS_SetErrorReporter(cx
, my_ErrorReporter
);
3798 JS_SetVersion(cx
, JSVERSION_LATEST
);
3799 SetContextOptions(cx
);
3805 main(int argc
, char **argv
, char **envp
)
3810 JSObject
*glob
, *it
, *envobj
;
3813 JavaVM
*java_vm
= NULL
;
3817 #ifdef JSDEBUGGER_JAVA_UI
3821 #ifdef JSDEBUGGER_C_UI
3823 #endif /* JSDEBUGGER_C_UI */
3824 #endif /* JSDEBUGGER */
3826 CheckHelpMessages();
3827 setlocale(LC_ALL
, "");
3829 gStackBase
= (jsuword
)&stackDummy
;
3832 /* these streams are normally line buffered on OS/2 and need a \n, *
3833 * so we need to unbuffer then to get a reasonable prompt */
3844 rt
= JS_NewRuntime(64L * 1024L * 1024L);
3847 JS_SetContextCallback(rt
, ContextCallback
);
3849 cx
= JS_NewContext(rt
, gStackChunkSize
);
3853 #ifdef JS_THREADSAFE
3854 JS_BeginRequest(cx
);
3857 glob
= JS_NewObject(cx
, &global_class
, NULL
, NULL
);
3860 #ifdef LAZY_STANDARD_CLASSES
3861 JS_SetGlobalObject(cx
, glob
);
3863 if (!JS_InitStandardClasses(cx
, glob
))
3866 if (!JS_DefineFunctions(cx
, glob
, shell_functions
))
3869 it
= JS_DefineObject(cx
, glob
, "it", &its_class
, NULL
, 0);
3872 if (!JS_DefineProperties(cx
, it
, its_props
))
3874 if (!JS_DefineFunctions(cx
, it
, its_methods
))
3879 * XXX A command line option to enable debugging (or not) would be good
3881 jsdc
= JSD_DebuggerOnForUser(rt
, NULL
, NULL
);
3884 JSD_JSContextInUse(jsdc
, cx
);
3885 #ifdef JSD_LOWLEVEL_SOURCE
3886 JS_SetSourceHandler(rt
, SendSourceToJSDebugger
, jsdc
);
3887 #endif /* JSD_LOWLEVEL_SOURCE */
3888 #ifdef JSDEBUGGER_JAVA_UI
3889 jsdjc
= JSDJ_CreateContext();
3892 JSDJ_SetJSDContext(jsdjc
, jsdc
);
3893 java_env
= JSDJ_CreateJavaVMAndStartDebugger(jsdjc
);
3896 (*java_env
)->GetJavaVM(java_env
, &java_vm
);
3899 * XXX This would be the place to wait for the debugger to start.
3900 * Waiting would be nice in general, but especially when a js file
3901 * is passed on the cmd line.
3903 #endif /* JSDEBUGGER_JAVA_UI */
3904 #ifdef JSDEBUGGER_C_UI
3905 jsdbc
= JSDB_InitDebugger(rt
, jsdc
, 0);
3906 #endif /* JSDEBUGGER_C_UI */
3907 #endif /* JSDEBUGGER */
3910 if (!JSJ_SimpleInit(cx
, glob
, java_vm
, getenv("CLASSPATH")))
3914 envobj
= JS_DefineObject(cx
, glob
, "environment", &env_class
, NULL
, 0);
3915 if (!envobj
|| !JS_SetPrivate(cx
, envobj
, envp
))
3921 static const char Object_prototype
[] = "Object.prototype";
3923 if (!JS_DefineFunction(cx
, glob
, "snarf", snarf
, 1, 0))
3925 if (!JS_DefineFunction(cx
, glob
, "evaluate", Evaluate
, 3, 0))
3928 if (!JS_EvaluateScript(cx
, glob
,
3929 Object_prototype
, sizeof Object_prototype
- 1,
3933 if (!JS_DefineFunction(cx
, JSVAL_TO_OBJECT(v
), "__defineProperty__",
3934 defineProperty
, 5, 0)) {
3940 result
= ProcessArgs(cx
, glob
, argv
, argc
);
3944 #ifdef JSDEBUGGER_C_UI
3946 JSDB_TermDebugger(jsdc
);
3947 #endif /* JSDEBUGGER_C_UI */
3948 JSD_DebuggerOff(jsdc
);
3950 #endif /* JSDEBUGGER */
3952 #ifdef JS_THREADSAFE
3956 JS_DestroyContext(cx
);
3957 JS_DestroyRuntime(rt
);