/[jscoverage]/trunk/js/js.cpp
ViewVC logotype

Annotation of /trunk/js/js.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 399 - (hide annotations)
Tue Dec 9 03:37:47 2008 UTC (13 years, 6 months ago) by siliconforks
File size: 112382 byte(s)
Use SpiderMonkey from Firefox 3.1b2.

1 siliconforks 332 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2     * vim: set ts=8 sw=4 et tw=99:
3     *
4     * ***** BEGIN LICENSE BLOCK *****
5     * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6     *
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/
11     *
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
15     * License.
16     *
17     * The Original Code is Mozilla Communicator client code, released
18     * March 31, 1998.
19     *
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.
24     *
25     * Contributor(s):
26     *
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.
38     *
39     * ***** END LICENSE BLOCK ***** */
40    
41     /*
42     * JS shell.
43     */
44     #include "jsstddef.h"
45     #include <errno.h>
46     #include <stdio.h>
47     #include <stdlib.h>
48     #include <string.h>
49     #include <locale.h>
50     #include "jstypes.h"
51     #include "jsarena.h"
52     #include "jsutil.h"
53     #include "jsprf.h"
54     #include "jsapi.h"
55     #include "jsarray.h"
56     #include "jsatom.h"
57 siliconforks 399 #include "jsbuiltins.h"
58 siliconforks 332 #include "jscntxt.h"
59     #include "jsdbgapi.h"
60     #include "jsemit.h"
61     #include "jsfun.h"
62     #include "jsgc.h"
63     #include "jslock.h"
64     #include "jsnum.h"
65     #include "jsobj.h"
66     #include "jsparse.h"
67     #include "jsscope.h"
68     #include "jsscript.h"
69    
70     #ifdef LIVECONNECT
71     #include "jsjava.h"
72     #endif
73    
74     #ifdef JSDEBUGGER
75     #include "jsdebug.h"
76     #ifdef JSDEBUGGER_JAVA_UI
77     #include "jsdjava.h"
78     #endif /* JSDEBUGGER_JAVA_UI */
79     #ifdef JSDEBUGGER_C_UI
80     #include "jsdb.h"
81     #endif /* JSDEBUGGER_C_UI */
82     #endif /* JSDEBUGGER */
83    
84     #ifdef XP_UNIX
85     #include <unistd.h>
86     #include <sys/types.h>
87     #include <sys/wait.h>
88     #endif
89    
90     #if defined(XP_WIN) || defined(XP_OS2)
91     #include <io.h> /* for isatty() */
92     #endif
93    
94     typedef enum JSShellExitCode {
95     EXITCODE_RUNTIME_ERROR = 3,
96     EXITCODE_FILE_NOT_FOUND = 4,
97     EXITCODE_OUT_OF_MEMORY = 5
98     } JSShellExitCode;
99    
100     size_t gStackChunkSize = 8192;
101    
102     /* Assume that we can not use more than 5e5 bytes of C stack by default. */
103     static size_t gMaxStackSize = 500000;
104     static jsuword gStackBase;
105    
106     static size_t gScriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
107    
108     static JSBool gEnableBranchCallback = JS_FALSE;
109     static uint32 gBranchCount;
110     static uint32 gBranchLimit;
111    
112     int gExitCode = 0;
113     JSBool gQuitting = JS_FALSE;
114     FILE *gErrFile = NULL;
115     FILE *gOutFile = NULL;
116    
117     static JSBool reportWarnings = JS_TRUE;
118     static JSBool compileOnly = JS_FALSE;
119    
120     typedef enum JSShellErrNum {
121     #define MSG_DEF(name, number, count, exception, format) \
122     name = number,
123     #include "jsshell.msg"
124     #undef MSG_DEF
125     JSShellErr_Limit
126     #undef MSGDEF
127     } JSShellErrNum;
128    
129     static const JSErrorFormatString *
130     my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber);
131     static JSObject *
132     split_setup(JSContext *cx);
133    
134     #ifdef EDITLINE
135     JS_BEGIN_EXTERN_C
136     extern char *readline(const char *prompt);
137     extern void add_history(char *line);
138     JS_END_EXTERN_C
139     #endif
140    
141     static JSBool
142     GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
143     #ifdef EDITLINE
144     /*
145     * Use readline only if file is stdin, because there's no way to specify
146     * another handle. Are other filehandles interactive?
147     */
148     if (file == stdin) {
149     char *linep = readline(prompt);
150     if (!linep)
151     return JS_FALSE;
152     if (linep[0] != '\0')
153     add_history(linep);
154     strcpy(bufp, linep);
155     JS_free(cx, linep);
156     bufp += strlen(bufp);
157     *bufp++ = '\n';
158     *bufp = '\0';
159     } else
160     #endif
161     {
162     char line[256];
163     fprintf(gOutFile, prompt);
164     fflush(gOutFile);
165     if (!fgets(line, sizeof line, file))
166     return JS_FALSE;
167     strcpy(bufp, line);
168     }
169     return JS_TRUE;
170     }
171    
172     static JSBool
173     my_BranchCallback(JSContext *cx, JSScript *script)
174     {
175     if (++gBranchCount == gBranchLimit) {
176     if (script) {
177     if (script->filename)
178     fprintf(gErrFile, "%s:", script->filename);
179     fprintf(gErrFile, "%u: script branch callback (%u callbacks)\n",
180     script->lineno, gBranchLimit);
181     } else {
182     fprintf(gErrFile, "native branch callback (%u callbacks)\n",
183     gBranchLimit);
184     }
185     gBranchCount = 0;
186     return JS_FALSE;
187     }
188     #ifdef JS_THREADSAFE
189     if ((gBranchCount & 0xff) == 1) {
190     #endif
191     if ((gBranchCount & 0x3fff) == 1)
192     JS_MaybeGC(cx);
193     #ifdef JS_THREADSAFE
194     else
195     JS_YieldRequest(cx);
196     }
197     #endif
198     return JS_TRUE;
199     }
200    
201     static void
202     SetContextOptions(JSContext *cx)
203     {
204     jsuword stackLimit;
205    
206     if (gMaxStackSize == 0) {
207     /*
208     * Disable checking for stack overflow if limit is zero.
209     */
210     stackLimit = 0;
211     } else {
212     #if JS_STACK_GROWTH_DIRECTION > 0
213     stackLimit = gStackBase + gMaxStackSize;
214     #else
215     stackLimit = gStackBase - gMaxStackSize;
216     #endif
217     }
218     JS_SetThreadStackLimit(cx, stackLimit);
219     JS_SetScriptStackQuota(cx, gScriptStackQuota);
220     if (gEnableBranchCallback) {
221     JS_SetBranchCallback(cx, my_BranchCallback);
222     JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK);
223     }
224     }
225    
226     static void
227     Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
228     {
229     JSBool ok, hitEOF;
230     JSScript *script;
231     jsval result;
232     JSString *str;
233     char buffer[4096];
234     char *bufp;
235     int lineno;
236     int startline;
237     FILE *file;
238     uint32 oldopts;
239    
240     if (forceTTY || !filename || strcmp(filename, "-") == 0) {
241     file = stdin;
242     } else {
243     file = fopen(filename, "r");
244     if (!file) {
245     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
246     JSSMSG_CANT_OPEN, filename, strerror(errno));
247     gExitCode = EXITCODE_FILE_NOT_FOUND;
248     return;
249     }
250     }
251    
252     SetContextOptions(cx);
253    
254     if (!forceTTY && !isatty(fileno(file))) {
255     /*
256     * It's not interactive - just execute it.
257     *
258     * Support the UNIX #! shell hack; gobble the first line if it starts
259     * with '#'. TODO - this isn't quite compatible with sharp variables,
260     * as a legal js program (using sharp variables) might start with '#'.
261     * But that would require multi-character lookahead.
262     */
263     int ch = fgetc(file);
264     if (ch == '#') {
265     while((ch = fgetc(file)) != EOF) {
266     if (ch == '\n' || ch == '\r')
267     break;
268     }
269     }
270     ungetc(ch, file);
271    
272     oldopts = JS_GetOptions(cx);
273     JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
274     script = JS_CompileFileHandle(cx, obj, filename, file);
275     JS_SetOptions(cx, oldopts);
276     if (script) {
277     if (!compileOnly)
278     (void)JS_ExecuteScript(cx, obj, script, NULL);
279     JS_DestroyScript(cx, script);
280     }
281    
282     if (file != stdin)
283     fclose(file);
284     return;
285     }
286    
287     /* It's an interactive filehandle; drop into read-eval-print loop. */
288     lineno = 1;
289     hitEOF = JS_FALSE;
290     do {
291     bufp = buffer;
292     *bufp = '\0';
293    
294     /*
295     * Accumulate lines until we get a 'compilable unit' - one that either
296     * generates an error (before running out of source) or that compiles
297     * cleanly. This should be whenever we get a complete statement that
298     * coincides with the end of a line.
299     */
300     startline = lineno;
301     do {
302     if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
303     hitEOF = JS_TRUE;
304     break;
305     }
306     bufp += strlen(bufp);
307     lineno++;
308     } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
309    
310     /* Clear any pending exception from previous failed compiles. */
311     JS_ClearPendingException(cx);
312     script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein",
313     startline);
314     if (script) {
315     if (!compileOnly) {
316     ok = JS_ExecuteScript(cx, obj, script, &result);
317     if (ok && !JSVAL_IS_VOID(result)) {
318     str = JS_ValueToString(cx, result);
319     if (str)
320     fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
321     else
322     ok = JS_FALSE;
323     }
324     }
325     JS_DestroyScript(cx, script);
326     }
327     } while (!hitEOF && !gQuitting);
328     fprintf(gOutFile, "\n");
329     if (file != stdin)
330     fclose(file);
331     return;
332     }
333    
334     static int
335     usage(void)
336     {
337     fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
338     fprintf(gErrFile, "usage: js [-zKPswWxCi] [-b branchlimit] [-c stackchunksize] [-o option] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] "
339     #ifdef JS_GC_ZEAL
340     "[-Z gczeal] "
341     #endif
342     "[scriptfile] [scriptarg...]\n");
343     return 2;
344     }
345    
346     static struct {
347     const char *name;
348     uint32 flag;
349     } js_options[] = {
350     {"strict", JSOPTION_STRICT},
351     {"werror", JSOPTION_WERROR},
352     {"atline", JSOPTION_ATLINE},
353     {"xml", JSOPTION_XML},
354     {"relimit", JSOPTION_RELIMIT},
355     {"anonfunfix", JSOPTION_ANONFUNFIX},
356     {"jit", JSOPTION_JIT},
357     {NULL, 0}
358     };
359    
360     extern JSClass global_class;
361    
362     static int
363     ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
364     {
365     int i, j, length;
366     JSObject *argsObj;
367     char *filename = NULL;
368     JSBool isInteractive = JS_TRUE;
369     JSBool forceTTY = JS_FALSE;
370    
371     /*
372     * Scan past all optional arguments so we can create the arguments object
373     * before processing any -f options, which must interleave properly with
374     * -v and -w options. This requires two passes, and without getopt, we'll
375     * have to keep the option logic here and in the second for loop in sync.
376     */
377     for (i = 0; i < argc; i++) {
378     if (argv[i][0] != '-' || argv[i][1] == '\0') {
379     ++i;
380     break;
381     }
382     switch (argv[i][1]) {
383     case 'b':
384     case 'c':
385     case 'f':
386     case 'e':
387     case 'v':
388     case 'S':
389     #ifdef JS_GC_ZEAL
390     case 'Z':
391     #endif
392     ++i;
393     break;
394     default:;
395     }
396     }
397    
398     /*
399     * Create arguments early and define it to root it, so it's safe from any
400     * GC calls nested below, and so it is available to -f <file> arguments.
401     */
402     argsObj = JS_NewArrayObject(cx, 0, NULL);
403     if (!argsObj)
404     return 1;
405     if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
406     NULL, NULL, 0)) {
407     return 1;
408     }
409    
410     length = argc - i;
411     for (j = 0; j < length; j++) {
412     JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
413     if (!str)
414     return 1;
415     if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str),
416     NULL, NULL, JSPROP_ENUMERATE)) {
417     return 1;
418     }
419     }
420    
421     for (i = 0; i < argc; i++) {
422     if (argv[i][0] != '-' || argv[i][1] == '\0') {
423     filename = argv[i++];
424     isInteractive = JS_FALSE;
425     break;
426     }
427    
428     switch (argv[i][1]) {
429     case 'v':
430     if (++i == argc)
431     return usage();
432    
433     JS_SetVersion(cx, (JSVersion) atoi(argv[i]));
434     break;
435    
436     #ifdef JS_GC_ZEAL
437     case 'Z':
438     if (++i == argc)
439     return usage();
440     JS_SetGCZeal(cx, atoi(argv[i]));
441     break;
442     #endif
443    
444     case 'w':
445     reportWarnings = JS_TRUE;
446     break;
447    
448     case 'W':
449     reportWarnings = JS_FALSE;
450     break;
451    
452     case 's':
453     JS_ToggleOptions(cx, JSOPTION_STRICT);
454     break;
455    
456     case 'E':
457     JS_ToggleOptions(cx, JSOPTION_RELIMIT);
458     break;
459    
460     case 'x':
461     JS_ToggleOptions(cx, JSOPTION_XML);
462     break;
463    
464     case 'j':
465     JS_ToggleOptions(cx, JSOPTION_JIT);
466     #if defined(JS_TRACER) && defined(DEBUG)
467     extern struct JSClass jitstats_class;
468     extern void js_InitJITStatsClass(JSContext *cx, JSObject *glob);
469     js_InitJITStatsClass(cx, JS_GetGlobalObject(cx));
470     JS_DefineObject(cx, JS_GetGlobalObject(cx), "tracemonkey",
471     &jitstats_class, NULL, 0);
472     #endif
473     break;
474    
475     case 'o':
476     if (++i == argc)
477     return usage();
478    
479     for (j = 0; js_options[j].name; ++j) {
480     if (strcmp(js_options[j].name, argv[i]) == 0) {
481     JS_ToggleOptions(cx, js_options[j].flag);
482     break;
483     }
484     }
485     break;
486    
487     case 'P':
488     if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) {
489     JSObject *gobj;
490    
491     if (!JS_SealObject(cx, obj, JS_TRUE))
492     return JS_FALSE;
493     gobj = JS_NewObject(cx, &global_class, NULL, NULL);
494     if (!gobj)
495     return JS_FALSE;
496     if (!JS_SetPrototype(cx, gobj, obj))
497     return JS_FALSE;
498     JS_SetParent(cx, gobj, NULL);
499     JS_SetGlobalObject(cx, gobj);
500     obj = gobj;
501     }
502     break;
503    
504     case 'b':
505     gBranchLimit = atoi(argv[++i]);
506     gEnableBranchCallback = (gBranchLimit != 0);
507     break;
508    
509     case 'c':
510     /* set stack chunk size */
511     gStackChunkSize = atoi(argv[++i]);
512     break;
513    
514     case 'f':
515     if (++i == argc)
516     return usage();
517    
518     Process(cx, obj, argv[i], JS_FALSE);
519    
520     /*
521     * XXX: js -f foo.js should interpret foo.js and then
522     * drop into interactive mode, but that breaks the test
523     * harness. Just execute foo.js for now.
524     */
525     isInteractive = JS_FALSE;
526     break;
527    
528     case 'e':
529     {
530     jsval rval;
531    
532     if (++i == argc)
533     return usage();
534    
535     /* Pass a filename of -e to imitate PERL */
536     JS_EvaluateScript(cx, obj, argv[i], strlen(argv[i]),
537     "-e", 1, &rval);
538    
539     isInteractive = JS_FALSE;
540     break;
541    
542     }
543     case 'C':
544     compileOnly = JS_TRUE;
545     isInteractive = JS_FALSE;
546     break;
547    
548     case 'i':
549     isInteractive = forceTTY = JS_TRUE;
550     break;
551    
552     case 'S':
553     if (++i == argc)
554     return usage();
555    
556     /* Set maximum stack size. */
557     gMaxStackSize = atoi(argv[i]);
558     break;
559    
560     case 'z':
561     obj = split_setup(cx);
562     if (!obj)
563     return gExitCode;
564     break;
565     #ifdef MOZ_SHARK
566     case 'k':
567     JS_ConnectShark();
568     break;
569     #endif
570     default:
571     return usage();
572     }
573     }
574    
575     if (filename || isInteractive)
576     Process(cx, obj, filename, forceTTY);
577     return gExitCode;
578     }
579    
580     static JSBool
581     Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
582     {
583     if (argc > 0 && JSVAL_IS_INT(argv[0]))
584     *rval = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0])));
585     else
586     *rval = INT_TO_JSVAL(JS_GetVersion(cx));
587     return JS_TRUE;
588     }
589    
590     static JSBool
591     Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
592     {
593     uint32 optset, flag;
594     uintN i, j, found;
595     JSString *str;
596     const char *opt;
597     char *names;
598    
599     optset = 0;
600     for (i = 0; i < argc; i++) {
601     str = JS_ValueToString(cx, argv[i]);
602     if (!str)
603     return JS_FALSE;
604     opt = JS_GetStringBytes(str);
605     for (j = 0; js_options[j].name; j++) {
606     if (strcmp(js_options[j].name, opt) == 0) {
607     optset |= js_options[j].flag;
608     break;
609     }
610     }
611     }
612     optset = JS_ToggleOptions(cx, optset);
613    
614     names = NULL;
615     found = 0;
616     while (optset != 0) {
617     flag = optset;
618     optset &= optset - 1;
619     flag &= ~optset;
620     for (j = 0; js_options[j].name; j++) {
621     if (js_options[j].flag == flag) {
622     names = JS_sprintf_append(names, "%s%s",
623     names ? "," : "", js_options[j].name);
624     found++;
625     break;
626     }
627     }
628     }
629     if (!found)
630     names = strdup("");
631     if (!names) {
632     JS_ReportOutOfMemory(cx);
633     return JS_FALSE;
634     }
635    
636     str = JS_NewString(cx, names, strlen(names));
637     if (!str) {
638     free(names);
639     return JS_FALSE;
640     }
641     *rval = STRING_TO_JSVAL(str);
642     return JS_TRUE;
643     }
644    
645     static JSBool
646     Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
647     {
648     uintN i;
649     JSString *str;
650     const char *filename;
651     JSScript *script;
652     JSBool ok;
653     uint32 oldopts;
654    
655     for (i = 0; i < argc; i++) {
656     str = JS_ValueToString(cx, argv[i]);
657     if (!str)
658     return JS_FALSE;
659     argv[i] = STRING_TO_JSVAL(str);
660     filename = JS_GetStringBytes(str);
661     errno = 0;
662     oldopts = JS_GetOptions(cx);
663     JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
664     script = JS_CompileFile(cx, obj, filename);
665     JS_SetOptions(cx, oldopts);
666     if (!script) {
667     ok = JS_FALSE;
668     } else {
669     ok = !compileOnly
670     ? JS_ExecuteScript(cx, obj, script, NULL)
671     : JS_TRUE;
672     JS_DestroyScript(cx, script);
673     }
674     if (!ok)
675     return JS_FALSE;
676     }
677    
678     return JS_TRUE;
679     }
680    
681     /*
682     * function readline()
683     * Provides a hook for scripts to read a line from stdin.
684     */
685     static JSBool
686     ReadLine(JSContext *cx, uintN argc, jsval *vp)
687     {
688     #define BUFSIZE 256
689     FILE *from;
690     char *buf, *tmp;
691     size_t bufsize, buflength, gotlength;
692     JSBool sawNewline;
693     JSString *str;
694    
695     from = stdin;
696     buflength = 0;
697     bufsize = BUFSIZE;
698     buf = (char *) JS_malloc(cx, bufsize);
699     if (!buf)
700     return JS_FALSE;
701    
702     sawNewline = JS_FALSE;
703     while ((gotlength =
704     js_fgets(buf + buflength, bufsize - buflength, from)) > 0) {
705     buflength += gotlength;
706    
707     /* Are we done? */
708     if (buf[buflength - 1] == '\n') {
709     buf[buflength - 1] = '\0';
710     sawNewline = JS_TRUE;
711     break;
712     } else if (buflength < bufsize - 1) {
713     break;
714     }
715    
716     /* Else, grow our buffer for another pass. */
717     bufsize *= 2;
718     if (bufsize > buflength) {
719     tmp = (char *) JS_realloc(cx, buf, bufsize);
720     } else {
721     JS_ReportOutOfMemory(cx);
722     tmp = NULL;
723     }
724    
725     if (!tmp) {
726     JS_free(cx, buf);
727     return JS_FALSE;
728     }
729    
730     buf = tmp;
731     }
732    
733     /* Treat the empty string specially. */
734     if (buflength == 0) {
735     *vp = feof(from) ? JSVAL_NULL : JS_GetEmptyStringValue(cx);
736     JS_free(cx, buf);
737     return JS_TRUE;
738     }
739    
740     /* Shrink the buffer to the real size. */
741     tmp = (char *) JS_realloc(cx, buf, buflength);
742     if (!tmp) {
743     JS_free(cx, buf);
744     return JS_FALSE;
745     }
746    
747     buf = tmp;
748    
749     /*
750     * Turn buf into a JSString. Note that buflength includes the trailing null
751     * character.
752     */
753     str = JS_NewString(cx, buf, sawNewline ? buflength - 1 : buflength);
754     if (!str) {
755     JS_free(cx, buf);
756     return JS_FALSE;
757     }
758    
759     *vp = STRING_TO_JSVAL(str);
760     return JS_TRUE;
761     }
762    
763 siliconforks 399 #ifdef JS_TRACER
764     static jsval JS_FASTCALL
765     Print_tn(JSContext *cx, JSString *str)
766     {
767     char *bytes = JS_EncodeString(cx, str);
768     if (!bytes)
769     return JSVAL_ERROR_COOKIE;
770     fprintf(gOutFile, "%s\n", bytes);
771     JS_free(cx, bytes);
772     fflush(gOutFile);
773     return JSVAL_VOID;
774     }
775     #endif
776    
777 siliconforks 332 static JSBool
778     Print(JSContext *cx, uintN argc, jsval *vp)
779     {
780     jsval *argv;
781     uintN i;
782     JSString *str;
783     char *bytes;
784    
785     argv = JS_ARGV(cx, vp);
786     for (i = 0; i < argc; i++) {
787     str = JS_ValueToString(cx, argv[i]);
788     if (!str)
789     return JS_FALSE;
790     bytes = JS_EncodeString(cx, str);
791     if (!bytes)
792     return JS_FALSE;
793     fprintf(gOutFile, "%s%s", i ? " " : "", bytes);
794     JS_free(cx, bytes);
795     }
796    
797     fputc('\n', gOutFile);
798     fflush(gOutFile);
799    
800     JS_SET_RVAL(cx, vp, JSVAL_VOID);
801     return JS_TRUE;
802     }
803    
804     static JSBool
805     Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
806    
807     static JSBool
808     Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
809     {
810     #ifdef LIVECONNECT
811     JSJ_SimpleShutdown();
812     #endif
813    
814     JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode);
815    
816     gQuitting = JS_TRUE;
817     return JS_FALSE;
818     }
819    
820     static JSBool
821     GC(JSContext *cx, uintN argc, jsval *vp)
822     {
823     JSRuntime *rt;
824     uint32 preBytes;
825    
826     rt = cx->runtime;
827     preBytes = rt->gcBytes;
828     JS_GC(cx);
829    
830     fprintf(gOutFile, "before %lu, after %lu, break %08lx\n",
831     (unsigned long)preBytes, (unsigned long)rt->gcBytes,
832     #ifdef XP_UNIX
833     (unsigned long)sbrk(0)
834     #else
835     0
836     #endif
837     );
838     #ifdef JS_GCMETER
839     js_DumpGCStats(rt, stdout);
840     #endif
841     *vp = JSVAL_VOID;
842     return JS_TRUE;
843     }
844    
845     static JSBool
846     GCParameter(JSContext *cx, uintN argc, jsval *vp)
847     {
848     JSString *str;
849     const char *paramName;
850     JSGCParamKey param;
851     uint32 value;
852    
853     if (argc == 0) {
854     str = JS_ValueToString(cx, JSVAL_VOID);
855     JS_ASSERT(str);
856     } else {
857     str = JS_ValueToString(cx, vp[2]);
858     if (!str)
859     return JS_FALSE;
860     vp[2] = STRING_TO_JSVAL(str);
861     }
862     paramName = JS_GetStringBytes(str);
863     if (!paramName)
864     return JS_FALSE;
865     if (strcmp(paramName, "maxBytes") == 0) {
866     param = JSGC_MAX_BYTES;
867     } else if (strcmp(paramName, "maxMallocBytes") == 0) {
868     param = JSGC_MAX_MALLOC_BYTES;
869     } else {
870     JS_ReportError(cx,
871     "the first argument argument must be either maxBytes "
872     "or maxMallocBytes");
873     return JS_FALSE;
874     }
875    
876     if (!JS_ValueToECMAUint32(cx, argc < 2 ? JSVAL_VOID : vp[3], &value))
877     return JS_FALSE;
878     if (value == 0) {
879     JS_ReportError(cx,
880     "the second argument must be convertable to uint32 with "
881     "non-zero value");
882     return JS_FALSE;
883     }
884     JS_SetGCParameter(cx->runtime, param, value);
885     *vp = JSVAL_VOID;
886     return JS_TRUE;
887     }
888    
889     #ifdef JS_GC_ZEAL
890     static JSBool
891     GCZeal(JSContext *cx, uintN argc, jsval *vp)
892     {
893     uint32 zeal;
894    
895     if (!JS_ValueToECMAUint32(cx, argc == 0 ? JSVAL_VOID : vp[2], &zeal))
896     return JS_FALSE;
897     JS_SetGCZeal(cx, (uint8)zeal);
898     *vp = JSVAL_VOID;
899     return JS_TRUE;
900     }
901     #endif /* JS_GC_ZEAL */
902    
903     typedef struct JSCountHeapNode JSCountHeapNode;
904    
905     struct JSCountHeapNode {
906     void *thing;
907     int32 kind;
908     JSCountHeapNode *next;
909     };
910    
911     typedef struct JSCountHeapTracer {
912     JSTracer base;
913     JSDHashTable visited;
914     JSBool ok;
915     JSCountHeapNode *traceList;
916     JSCountHeapNode *recycleList;
917     } JSCountHeapTracer;
918    
919     static void
920     CountHeapNotify(JSTracer *trc, void *thing, uint32 kind)
921     {
922     JSCountHeapTracer *countTracer;
923     JSDHashEntryStub *entry;
924     JSCountHeapNode *node;
925    
926     JS_ASSERT(trc->callback == CountHeapNotify);
927     countTracer = (JSCountHeapTracer *)trc;
928     if (!countTracer->ok)
929     return;
930    
931     entry = (JSDHashEntryStub *)
932     JS_DHashTableOperate(&countTracer->visited, thing, JS_DHASH_ADD);
933     if (!entry) {
934     JS_ReportOutOfMemory(trc->context);
935     countTracer->ok = JS_FALSE;
936     return;
937     }
938     if (entry->key)
939     return;
940     entry->key = thing;
941    
942     node = countTracer->recycleList;
943     if (node) {
944     countTracer->recycleList = node->next;
945     } else {
946     node = (JSCountHeapNode *) JS_malloc(trc->context, sizeof *node);
947     if (!node) {
948     countTracer->ok = JS_FALSE;
949     return;
950     }
951     }
952     node->thing = thing;
953     node->kind = kind;
954     node->next = countTracer->traceList;
955     countTracer->traceList = node;
956     }
957    
958     static JSBool
959     CountHeap(JSContext *cx, uintN argc, jsval *vp)
960     {
961     void* startThing;
962     int32 startTraceKind;
963     jsval v;
964     int32 traceKind, i;
965     JSString *str;
966     char *bytes;
967     JSCountHeapTracer countTracer;
968     JSCountHeapNode *node;
969     size_t counter;
970    
971     static const struct {
972     const char *name;
973     int32 kind;
974     } traceKindNames[] = {
975     { "all", -1 },
976     { "object", JSTRACE_OBJECT },
977     { "double", JSTRACE_DOUBLE },
978     { "string", JSTRACE_STRING },
979     #if JS_HAS_XML_SUPPORT
980     { "xml", JSTRACE_XML },
981     #endif
982     };
983    
984     startThing = NULL;
985     startTraceKind = 0;
986     if (argc > 0) {
987     v = JS_ARGV(cx, vp)[0];
988     if (JSVAL_IS_TRACEABLE(v)) {
989     startThing = JSVAL_TO_TRACEABLE(v);
990     startTraceKind = JSVAL_TRACE_KIND(v);
991     } else if (v != JSVAL_NULL) {
992     JS_ReportError(cx,
993     "the first argument is not null or a heap-allocated "
994     "thing");
995     return JS_FALSE;
996     }
997     }
998    
999     traceKind = -1;
1000     if (argc > 1) {
1001     str = JS_ValueToString(cx, JS_ARGV(cx, vp)[1]);
1002     if (!str)
1003     return JS_FALSE;
1004     bytes = JS_GetStringBytes(str);
1005     if (!bytes)
1006     return JS_FALSE;
1007     for (i = 0; ;) {
1008     if (strcmp(bytes, traceKindNames[i].name) == 0) {
1009     traceKind = traceKindNames[i].kind;
1010     break;
1011     }
1012     if (++i == JS_ARRAY_LENGTH(traceKindNames)) {
1013     JS_ReportError(cx, "trace kind name '%s' is unknown", bytes);
1014     return JS_FALSE;
1015     }
1016     }
1017     }
1018    
1019     JS_TRACER_INIT(&countTracer.base, cx, CountHeapNotify);
1020     if (!JS_DHashTableInit(&countTracer.visited, JS_DHashGetStubOps(),
1021     NULL, sizeof(JSDHashEntryStub),
1022     JS_DHASH_DEFAULT_CAPACITY(100))) {
1023     JS_ReportOutOfMemory(cx);
1024     return JS_FALSE;
1025     }
1026     countTracer.ok = JS_TRUE;
1027     countTracer.traceList = NULL;
1028     countTracer.recycleList = NULL;
1029    
1030     if (!startThing) {
1031     JS_TraceRuntime(&countTracer.base);
1032     } else {
1033     JS_SET_TRACING_NAME(&countTracer.base, "root");
1034     JS_CallTracer(&countTracer.base, startThing, startTraceKind);
1035     }
1036    
1037     counter = 0;
1038     while ((node = countTracer.traceList) != NULL) {
1039     if (traceKind == -1 || node->kind == traceKind)
1040     counter++;
1041     countTracer.traceList = node->next;
1042     node->next = countTracer.recycleList;
1043     countTracer.recycleList = node;
1044     JS_TraceChildren(&countTracer.base, node->thing, node->kind);
1045     }
1046     while ((node = countTracer.recycleList) != NULL) {
1047     countTracer.recycleList = node->next;
1048     JS_free(cx, node);
1049     }
1050     JS_DHashTableFinish(&countTracer.visited);
1051    
1052     return countTracer.ok && JS_NewNumberValue(cx, (jsdouble) counter, vp);
1053     }
1054    
1055     static JSScript *
1056     ValueToScript(JSContext *cx, jsval v)
1057     {
1058     JSScript *script;
1059     JSFunction *fun;
1060    
1061     if (!JSVAL_IS_PRIMITIVE(v) &&
1062     JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) {
1063     script = (JSScript *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
1064     } else {
1065     fun = JS_ValueToFunction(cx, v);
1066     if (!fun)
1067     return NULL;
1068     script = FUN_SCRIPT(fun);
1069     }
1070    
1071     if (!script) {
1072     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
1073     JSSMSG_SCRIPTS_ONLY);
1074     }
1075    
1076     return script;
1077     }
1078    
1079     static JSBool
1080     GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
1081     int32 *ip)
1082     {
1083     jsval v;
1084     uintN intarg;
1085     JSScript *script;
1086    
1087     *scriptp = cx->fp->down->script;
1088     *ip = 0;
1089     if (argc != 0) {
1090     v = argv[0];
1091     intarg = 0;
1092     if (!JSVAL_IS_PRIMITIVE(v) &&
1093     (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass ||
1094     JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass)) {
1095     script = ValueToScript(cx, v);
1096     if (!script)
1097     return JS_FALSE;
1098     *scriptp = script;
1099     intarg++;
1100     }
1101     if (argc > intarg) {
1102     if (!JS_ValueToInt32(cx, argv[intarg], ip))
1103     return JS_FALSE;
1104     }
1105     }
1106     return JS_TRUE;
1107     }
1108    
1109     static JSTrapStatus
1110     TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
1111     void *closure)
1112     {
1113     JSString *str;
1114     JSStackFrame *caller;
1115    
1116     str = (JSString *) closure;
1117     caller = JS_GetScriptedCaller(cx, NULL);
1118     if (!JS_EvaluateScript(cx, caller->scopeChain,
1119     JS_GetStringBytes(str), JS_GetStringLength(str),
1120     caller->script->filename, caller->script->lineno,
1121     rval)) {
1122     return JSTRAP_ERROR;
1123     }
1124     if (!JSVAL_IS_VOID(*rval))
1125     return JSTRAP_RETURN;
1126     return JSTRAP_CONTINUE;
1127     }
1128    
1129     static JSBool
1130     Trap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1131     {
1132     JSString *str;
1133     JSScript *script;
1134     int32 i;
1135    
1136     if (argc == 0) {
1137     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_TRAP_USAGE);
1138     return JS_FALSE;
1139     }
1140     argc--;
1141     str = JS_ValueToString(cx, argv[argc]);
1142     if (!str)
1143     return JS_FALSE;
1144     argv[argc] = STRING_TO_JSVAL(str);
1145     if (!GetTrapArgs(cx, argc, argv, &script, &i))
1146     return JS_FALSE;
1147     return JS_SetTrap(cx, script, script->code + i, TrapHandler, str);
1148     }
1149    
1150     static JSBool
1151     Untrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1152     {
1153     JSScript *script;
1154     int32 i;
1155    
1156     if (!GetTrapArgs(cx, argc, argv, &script, &i))
1157     return JS_FALSE;
1158     JS_ClearTrap(cx, script, script->code + i, NULL, NULL);
1159     return JS_TRUE;
1160     }
1161    
1162     static JSBool
1163     LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1164     {
1165     JSScript *script;
1166     int32 i;
1167     uintN lineno;
1168     jsbytecode *pc;
1169    
1170     if (argc == 0) {
1171     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
1172     return JS_FALSE;
1173     }
1174     script = cx->fp->down->script;
1175     if (!GetTrapArgs(cx, argc, argv, &script, &i))
1176     return JS_FALSE;
1177     lineno = (i == 0) ? script->lineno : (uintN)i;
1178     pc = JS_LineNumberToPC(cx, script, lineno);
1179     if (!pc)
1180     return JS_FALSE;
1181     *rval = INT_TO_JSVAL(PTRDIFF(pc, script->code, jsbytecode));
1182     return JS_TRUE;
1183     }
1184    
1185     static JSBool
1186     PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1187     {
1188     JSScript *script;
1189     int32 i;
1190     uintN lineno;
1191    
1192     if (!GetTrapArgs(cx, argc, argv, &script, &i))
1193     return JS_FALSE;
1194     lineno = JS_PCToLineNumber(cx, script, script->code + i);
1195     if (!lineno)
1196     return JS_FALSE;
1197     *rval = INT_TO_JSVAL(lineno);
1198     return JS_TRUE;
1199     }
1200    
1201     #ifdef DEBUG
1202    
1203     static void
1204     UpdateSwitchTableBounds(JSScript *script, uintN offset,
1205     uintN *start, uintN *end)
1206     {
1207     jsbytecode *pc;
1208     JSOp op;
1209     ptrdiff_t jmplen;
1210     jsint low, high, n;
1211    
1212     pc = script->code + offset;
1213     op = (JSOp) *pc;
1214     switch (op) {
1215     case JSOP_TABLESWITCHX:
1216     jmplen = JUMPX_OFFSET_LEN;
1217     goto jump_table;
1218     case JSOP_TABLESWITCH:
1219     jmplen = JUMP_OFFSET_LEN;
1220     jump_table:
1221     pc += jmplen;
1222     low = GET_JUMP_OFFSET(pc);
1223     pc += JUMP_OFFSET_LEN;
1224     high = GET_JUMP_OFFSET(pc);
1225     pc += JUMP_OFFSET_LEN;
1226     n = high - low + 1;
1227     break;
1228    
1229     case JSOP_LOOKUPSWITCHX:
1230     jmplen = JUMPX_OFFSET_LEN;
1231     goto lookup_table;
1232     case JSOP_LOOKUPSWITCH:
1233     jmplen = JUMP_OFFSET_LEN;
1234     lookup_table:
1235     pc += jmplen;
1236     n = GET_INDEX(pc);
1237     pc += INDEX_LEN;
1238     jmplen += JUMP_OFFSET_LEN;
1239     break;
1240    
1241     default:
1242     /* [condswitch] switch does not have any jump or lookup tables. */
1243     JS_ASSERT(op == JSOP_CONDSWITCH);
1244     return;
1245     }
1246    
1247     *start = (uintN)(pc - script->code);
1248     *end = *start + (uintN)(n * jmplen);
1249     }
1250    
1251     static void
1252     SrcNotes(JSContext *cx, JSScript *script)
1253     {
1254     uintN offset, delta, caseOff, switchTableStart, switchTableEnd;
1255     jssrcnote *notes, *sn;
1256     JSSrcNoteType type;
1257     const char *name;
1258     uint32 index;
1259     JSAtom *atom;
1260     JSString *str;
1261    
1262     fprintf(gOutFile, "\nSource notes:\n");
1263     offset = 0;
1264     notes = SCRIPT_NOTES(script);
1265     switchTableEnd = switchTableStart = 0;
1266     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1267     delta = SN_DELTA(sn);
1268     offset += delta;
1269     type = (JSSrcNoteType) SN_TYPE(sn);
1270     name = js_SrcNoteSpec[type].name;
1271     if (type == SRC_LABEL) {
1272     /* Check if the source note is for a switch case. */
1273     if (switchTableStart <= offset && offset < switchTableEnd) {
1274     name = "case";
1275     } else {
1276     JS_ASSERT(script->code[offset] == JSOP_NOP);
1277     }
1278     }
1279     fprintf(gOutFile, "%3u: %5u [%4u] %-8s",
1280     (uintN) PTRDIFF(sn, notes, jssrcnote), offset, delta, name);
1281     switch (type) {
1282     case SRC_SETLINE:
1283     fprintf(gOutFile, " lineno %u", (uintN) js_GetSrcNoteOffset(sn, 0));
1284     break;
1285     case SRC_FOR:
1286     fprintf(gOutFile, " cond %u update %u tail %u",
1287     (uintN) js_GetSrcNoteOffset(sn, 0),
1288     (uintN) js_GetSrcNoteOffset(sn, 1),
1289     (uintN) js_GetSrcNoteOffset(sn, 2));
1290     break;
1291     case SRC_IF_ELSE:
1292     fprintf(gOutFile, " else %u elseif %u",
1293     (uintN) js_GetSrcNoteOffset(sn, 0),
1294     (uintN) js_GetSrcNoteOffset(sn, 1));
1295     break;
1296     case SRC_COND:
1297     case SRC_WHILE:
1298     case SRC_PCBASE:
1299     case SRC_PCDELTA:
1300     case SRC_DECL:
1301     case SRC_BRACE:
1302     fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0));
1303     break;
1304     case SRC_LABEL:
1305     case SRC_LABELBRACE:
1306     case SRC_BREAK2LABEL:
1307     case SRC_CONT2LABEL:
1308     index = js_GetSrcNoteOffset(sn, 0);
1309     JS_GET_SCRIPT_ATOM(script, index, atom);
1310     JS_ASSERT(ATOM_IS_STRING(atom));
1311     str = ATOM_TO_STRING(atom);
1312     fprintf(gOutFile, " atom %u (", index);
1313     js_FileEscapedString(gOutFile, str, 0);
1314     putc(')', gOutFile);
1315     break;
1316     case SRC_FUNCDEF: {
1317     const char *bytes;
1318     JSObject *obj;
1319     JSFunction *fun;
1320    
1321     index = js_GetSrcNoteOffset(sn, 0);
1322     JS_GET_SCRIPT_OBJECT(script, index, obj);
1323     fun = (JSFunction *) JS_GetPrivate(cx, obj);
1324     str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
1325     bytes = str ? JS_GetStringBytes(str) : "N/A";
1326     fprintf(gOutFile, " function %u (%s)", index, bytes);
1327     break;
1328     }
1329     case SRC_SWITCH:
1330     fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0));
1331     caseOff = (uintN) js_GetSrcNoteOffset(sn, 1);
1332     if (caseOff)
1333     fprintf(gOutFile, " first case offset %u", caseOff);
1334     UpdateSwitchTableBounds(script, offset,
1335     &switchTableStart, &switchTableEnd);
1336     break;
1337     case SRC_CATCH:
1338     delta = (uintN) js_GetSrcNoteOffset(sn, 0);
1339     if (delta) {
1340     if (script->main[offset] == JSOP_LEAVEBLOCK)
1341     fprintf(gOutFile, " stack depth %u", delta);
1342     else
1343     fprintf(gOutFile, " guard delta %u", delta);
1344     }
1345     break;
1346     default:;
1347     }
1348     fputc('\n', gOutFile);
1349     }
1350     }
1351    
1352     static JSBool
1353     Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1354     {
1355     uintN i;
1356     JSScript *script;
1357    
1358     for (i = 0; i < argc; i++) {
1359     script = ValueToScript(cx, argv[i]);
1360     if (!script)
1361     continue;
1362    
1363     SrcNotes(cx, script);
1364     }
1365     return JS_TRUE;
1366     }
1367    
1368 siliconforks 399 JS_STATIC_ASSERT(JSTRY_CATCH == 0);
1369     JS_STATIC_ASSERT(JSTRY_FINALLY == 1);
1370     JS_STATIC_ASSERT(JSTRY_ITER == 2);
1371 siliconforks 332
1372     static const char* const TryNoteNames[] = { "catch", "finally", "iter" };
1373    
1374     static JSBool
1375     TryNotes(JSContext *cx, JSScript *script)
1376     {
1377     JSTryNote *tn, *tnlimit;
1378    
1379     if (script->trynotesOffset == 0)
1380     return JS_TRUE;
1381    
1382     tn = JS_SCRIPT_TRYNOTES(script)->vector;
1383     tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length;
1384     fprintf(gOutFile, "\nException table:\n"
1385     "kind stack start end\n");
1386     do {
1387     JS_ASSERT(tn->kind < JS_ARRAY_LENGTH(TryNoteNames));
1388     fprintf(gOutFile, " %-7s %6u %8u %8u\n",
1389     TryNoteNames[tn->kind], tn->stackDepth,
1390     tn->start, tn->start + tn->length);
1391     } while (++tn != tnlimit);
1392     return JS_TRUE;
1393     }
1394    
1395     static JSBool
1396     Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1397     {
1398     JSBool lines;
1399     uintN i;
1400     JSScript *script;
1401    
1402     if (argc > 0 &&
1403     JSVAL_IS_STRING(argv[0]) &&
1404     !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), "-l")) {
1405     lines = JS_TRUE;
1406     argv++, argc--;
1407     } else {
1408     lines = JS_FALSE;
1409     }
1410     for (i = 0; i < argc; i++) {
1411     script = ValueToScript(cx, argv[i]);
1412     if (!script)
1413     return JS_FALSE;
1414     if (VALUE_IS_FUNCTION(cx, argv[i])) {
1415     JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
1416     if (fun && (fun->flags & JSFUN_FLAGS_MASK)) {
1417     uint16 flags = fun->flags;
1418     fputs("flags:", stdout);
1419    
1420     #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
1421    
1422     SHOW_FLAG(LAMBDA);
1423     SHOW_FLAG(SETTER);
1424     SHOW_FLAG(GETTER);
1425     SHOW_FLAG(BOUND_METHOD);
1426     SHOW_FLAG(HEAVYWEIGHT);
1427     SHOW_FLAG(THISP_STRING);
1428     SHOW_FLAG(THISP_NUMBER);
1429     SHOW_FLAG(THISP_BOOLEAN);
1430     SHOW_FLAG(EXPR_CLOSURE);
1431     SHOW_FLAG(INTERPRETED);
1432    
1433     #undef SHOW_FLAG
1434     putchar('\n');
1435     }
1436     }
1437    
1438     if (!js_Disassemble(cx, script, lines, stdout))
1439     return JS_FALSE;
1440     SrcNotes(cx, script);
1441     TryNotes(cx, script);
1442     }
1443     return JS_TRUE;
1444     }
1445    
1446     static JSBool
1447     DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1448     {
1449     JSString *str;
1450     const char *filename;
1451     JSScript *script;
1452     JSBool ok;
1453     uint32 oldopts;
1454    
1455     if (!argc)
1456     return JS_TRUE;
1457    
1458     str = JS_ValueToString(cx, argv[0]);
1459     if (!str)
1460     return JS_FALSE;
1461     argv[0] = STRING_TO_JSVAL(str);
1462    
1463     filename = JS_GetStringBytes(str);
1464     oldopts = JS_GetOptions(cx);
1465     JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
1466     script = JS_CompileFile(cx, obj, filename);
1467     JS_SetOptions(cx, oldopts);
1468     if (!script)
1469     return JS_FALSE;
1470    
1471     obj = JS_NewScriptObject(cx, script);
1472     if (!obj)
1473     return JS_FALSE;
1474    
1475     *rval = OBJECT_TO_JSVAL(obj); /* I like to root it, root it. */
1476     ok = Disassemble(cx, obj, 1, rval, rval); /* gross, but works! */
1477     *rval = JSVAL_VOID;
1478    
1479     return ok;
1480     }
1481    
1482     static JSBool
1483     DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
1484     jsval *rval)
1485     {
1486     #define LINE_BUF_LEN 512
1487     uintN i, len, line1, line2, bupline;
1488     JSScript *script;
1489     FILE *file;
1490     char linebuf[LINE_BUF_LEN];
1491     jsbytecode *pc, *end;
1492     JSBool ok;
1493     static char sep[] = ";-------------------------";
1494    
1495     ok = JS_TRUE;
1496     for (i = 0; ok && i < argc; i++) {
1497     script = ValueToScript(cx, argv[i]);
1498     if (!script)
1499     return JS_FALSE;
1500    
1501     if (!script->filename) {
1502     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
1503     JSSMSG_FILE_SCRIPTS_ONLY);
1504     return JS_FALSE;
1505     }
1506    
1507     file = fopen(script->filename, "r");
1508     if (!file) {
1509     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
1510     JSSMSG_CANT_OPEN, script->filename,
1511     strerror(errno));
1512     return JS_FALSE;
1513     }
1514    
1515     pc = script->code;
1516     end = pc + script->length;
1517    
1518     /* burn the leading lines */
1519     line2 = JS_PCToLineNumber(cx, script, pc);
1520     for (line1 = 0; line1 < line2 - 1; line1++)
1521     fgets(linebuf, LINE_BUF_LEN, file);
1522    
1523     bupline = 0;
1524     while (pc < end) {
1525     line2 = JS_PCToLineNumber(cx, script, pc);
1526    
1527     if (line2 < line1) {
1528     if (bupline != line2) {
1529     bupline = line2;
1530     fprintf(gOutFile, "%s %3u: BACKUP\n", sep, line2);
1531     }
1532     } else {
1533     if (bupline && line1 == line2)
1534     fprintf(gOutFile, "%s %3u: RESTORE\n", sep, line2);
1535     bupline = 0;
1536     while (line1 < line2) {
1537     if (!fgets(linebuf, LINE_BUF_LEN, file)) {
1538     JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
1539     JSSMSG_UNEXPECTED_EOF,
1540     script->filename);
1541     ok = JS_FALSE;
1542     goto bail;
1543     }
1544     line1++;
1545     fprintf(gOutFile, "%s %3u: %s", sep, line1, linebuf);
1546     }
1547     }
1548    
1549     len = js_Disassemble1(cx, script, pc,
1550     PTRDIFF(pc, script->code, jsbytecode),
1551     JS_TRUE, stdout);
1552     if (!len) {
1553     ok = JS_FALSE;
1554     goto bail;
1555     }
1556     pc += len;
1557     }
1558    
1559     bail:
1560     fclose(file);
1561     }
1562     return ok;
1563     #undef LINE_BUF_LEN
1564     }
1565    
1566     static JSBool
1567     Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1568     {
1569     JSBool bval;
1570     JSString *str;
1571    
1572     #if JS_THREADED_INTERP
1573     JS_ReportError(cx, "tracing not supported in JS_THREADED_INTERP builds");
1574     return JS_FALSE;
1575     #else
1576     if (argc == 0) {
1577     *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0);
1578     return JS_TRUE;
1579     }
1580    
1581     switch (JS_TypeOfValue(cx, argv[0])) {
1582     case JSTYPE_NUMBER:
1583     bval = JSVAL_IS_INT(argv[0])
1584     ? JSVAL_TO_INT(argv[0])
1585     : (jsint) *JSVAL_TO_DOUBLE(argv[0]);
1586     break;
1587     case JSTYPE_BOOLEAN:
1588     bval = JSVAL_TO_BOOLEAN(argv[0]);
1589     break;
1590     default:
1591     str = JS_ValueToString(cx, argv[0]);
1592     if (!str)
1593     return JS_FALSE;
1594     JS_ReportError(cx, "tracing: illegal argument %s",
1595     JS_GetStringBytes(str));
1596     return JS_FALSE;
1597     }
1598     cx->tracefp = bval ? stderr : NULL;
1599     return JS_TRUE;
1600     #endif
1601     }
1602    
1603     static void
1604     DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
1605     {
1606     uintN i;
1607     JSScope *scope;
1608     JSScopeProperty *sprop;
1609     jsval v;
1610     JSString *str;
1611    
1612     i = 0;
1613     scope = OBJ_SCOPE(obj);
1614     for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
1615     if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
1616     continue;
1617     fprintf(fp, "%3u %p ", i, (void *)sprop);
1618    
1619     v = ID_TO_VALUE(sprop->id);
1620     if (JSID_IS_INT(sprop->id)) {
1621     fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v));
1622     } else {
1623     if (JSID_IS_ATOM(sprop->id)) {
1624     str = JSVAL_TO_STRING(v);
1625     } else {
1626     JS_ASSERT(JSID_IS_OBJECT(sprop->id));
1627     str = js_ValueToString(cx, v);
1628     fputs("object ", fp);
1629     }
1630     if (!str)
1631     fputs("<error>", fp);
1632     else
1633     js_FileEscapedString(fp, str, '"');
1634     }
1635     #define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
1636     DUMP_ATTR(ENUMERATE);
1637     DUMP_ATTR(READONLY);
1638     DUMP_ATTR(PERMANENT);
1639     DUMP_ATTR(GETTER);
1640     DUMP_ATTR(SETTER);
1641     #undef DUMP_ATTR
1642    
1643     fprintf(fp, " slot %lu flags %x shortid %d\n",
1644     (unsigned long)sprop->slot, sprop->flags, sprop->shortid);
1645     }
1646     }
1647    
1648     static JSBool
1649     DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1650     {
1651     uintN i;
1652     JSString *str;
1653     const char *bytes;
1654     jsid id;
1655     JSObject *obj2;
1656     JSProperty *prop;
1657     jsval value;
1658    
1659     for (i = 0; i < argc; i++) {
1660     str = JS_ValueToString(cx, argv[i]);
1661     if (!str)
1662     return JS_FALSE;
1663     argv[i] = STRING_TO_JSVAL(str);
1664     bytes = JS_GetStringBytes(str);
1665     if (strcmp(bytes, "arena") == 0) {
1666     #ifdef JS_ARENAMETER
1667     JS_DumpArenaStats(stdout);
1668     #endif
1669     } else if (strcmp(bytes, "atom") == 0) {
1670     js_DumpAtoms(cx, gOutFile);
1671     } else if (strcmp(bytes, "global") == 0) {
1672     DumpScope(cx, cx->globalObject, stdout);
1673     } else {
1674     if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id))
1675     return JS_FALSE;
1676     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
1677     return JS_FALSE;
1678     if (prop) {
1679     OBJ_DROP_PROPERTY(cx, obj2, prop);
1680     if (!OBJ_GET_PROPERTY(cx, obj, id, &value))
1681     return JS_FALSE;
1682     }
1683     if (!prop || !JSVAL_IS_OBJECT(value)) {
1684     fprintf(gErrFile, "js: invalid stats argument %s\n",
1685     bytes);
1686     continue;
1687     }
1688     obj = JSVAL_TO_OBJECT(value);
1689     if (obj)
1690     DumpScope(cx, obj, stdout);
1691     }
1692     }
1693     return JS_TRUE;
1694     }
1695    
1696     static JSBool
1697     DumpHeap(JSContext *cx, uintN argc, jsval *vp)
1698     {
1699     char *fileName;
1700     jsval v;
1701     void* startThing;
1702     uint32 startTraceKind;
1703     const char *badTraceArg;
1704     void *thingToFind;
1705     size_t maxDepth;
1706     void *thingToIgnore;
1707     FILE *dumpFile;
1708     JSBool ok;
1709    
1710     fileName = NULL;
1711     if (argc > 0) {
1712     v = JS_ARGV(cx, vp)[0];
1713     if (v != JSVAL_NULL) {
1714     JSString *str;
1715    
1716     str = JS_ValueToString(cx, v);
1717     if (!str)
1718     return JS_FALSE;
1719     JS_ARGV(cx, vp)[0] = STRING_TO_JSVAL(str);
1720     fileName = JS_GetStringBytes(str);
1721     }
1722     }
1723    
1724     startThing = NULL;
1725     startTraceKind = 0;
1726     if (argc > 1) {
1727     v = JS_ARGV(cx, vp)[1];
1728     if (JSVAL_IS_TRACEABLE(v)) {
1729     startThing = JSVAL_TO_TRACEABLE(v);
1730     startTraceKind = JSVAL_TRACE_KIND(v);
1731     } else if (v != JSVAL_NULL) {
1732     badTraceArg = "start";
1733     goto not_traceable_arg;
1734     }
1735     }
1736    
1737     thingToFind = NULL;
1738     if (argc > 2) {
1739     v = JS_ARGV(cx, vp)[2];
1740     if (JSVAL_IS_TRACEABLE(v)) {
1741     thingToFind = JSVAL_TO_TRACEABLE(v);
1742     } else if (v != JSVAL_NULL) {
1743     badTraceArg = "toFind";
1744     goto not_traceable_arg;
1745     }
1746     }
1747    
1748     maxDepth = (size_t)-1;
1749     if (argc > 3) {
1750     v = JS_ARGV(cx, vp)[3];
1751     if (v != JSVAL_NULL) {
1752     uint32 depth;
1753    
1754     if (!JS_ValueToECMAUint32(cx, v, &depth))
1755     return JS_FALSE;
1756     maxDepth = depth;
1757     }
1758     }
1759    
1760     thingToIgnore = NULL;
1761     if (argc > 4) {
1762     v = JS_ARGV(cx, vp)[4];
1763     if (JSVAL_IS_TRACEABLE(v)) {
1764     thingToIgnore = JSVAL_TO_TRACEABLE(v);
1765     } else if (v != JSVAL_NULL) {
1766     badTraceArg = "toIgnore";
1767     goto not_traceable_arg;
1768     }
1769     }
1770    
1771     if (!fileName) {
1772     dumpFile = stdout;
1773     } else {
1774     dumpFile = fopen(fileName, "w");
1775     if (!dumpFile) {
1776     JS_ReportError(cx, "can't open %s: %s", fileName, strerror(errno));
1777     return JS_FALSE;
1778     }
1779     }
1780    
1781     ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
1782     maxDepth, thingToIgnore);
1783     if (dumpFile != stdout)
1784     fclose(dumpFile);
1785     return ok;
1786    
1787     not_traceable_arg:
1788     JS_ReportError(cx, "argument '%s' is not null or a heap-allocated thing",
1789     badTraceArg);
1790     return JS_FALSE;
1791     }
1792    
1793     #endif /* DEBUG */
1794    
1795     #ifdef TEST_CVTARGS
1796     #include <ctype.h>
1797    
1798     static const char *
1799     EscapeWideString(jschar *w)
1800     {
1801     static char enuf[80];
1802     static char hex[] = "0123456789abcdef";
1803     jschar u;
1804     unsigned char b, c;
1805     int i, j;
1806    
1807     if (!w)
1808     return "";
1809     for (i = j = 0; i < sizeof enuf - 1; i++, j++) {
1810     u = w[j];
1811     if (u == 0)
1812     break;
1813     b = (unsigned char)(u >> 8);
1814     c = (unsigned char)(u);
1815     if (b) {
1816     if (i >= sizeof enuf - 6)
1817     break;
1818     enuf[i++] = '\\';
1819     enuf[i++] = 'u';
1820     enuf[i++] = hex[b >> 4];
1821     enuf[i++] = hex[b & 15];
1822     enuf[i++] = hex[c >> 4];
1823     enuf[i] = hex[c & 15];
1824     } else if (!isprint(c)) {
1825     if (i >= sizeof enuf - 4)
1826     break;
1827     enuf[i++] = '\\';
1828     enuf[i++] = 'x';
1829     enuf[i++] = hex[c >> 4];
1830     enuf[i] = hex[c & 15];
1831     } else {
1832     enuf[i] = (char)c;
1833     }
1834     }
1835     enuf[i] = 0;
1836     return enuf;
1837     }
1838    
1839     #include <stdarg.h>
1840    
1841     static JSBool
1842     ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp,
1843     va_list *app)
1844     {
1845     jsval *vp;
1846     va_list ap;
1847     jsdouble re, im;
1848    
1849     printf("entering ZZ_formatter");
1850     vp = *vpp;
1851     ap = *app;
1852     if (fromJS) {
1853     if (!JS_ValueToNumber(cx, vp[0], &re))
1854     return JS_FALSE;
1855     if (!JS_ValueToNumber(cx, vp[1], &im))
1856     return JS_FALSE;
1857     *va_arg(ap, jsdouble *) = re;
1858     *va_arg(ap, jsdouble *) = im;
1859     } else {
1860     re = va_arg(ap, jsdouble);
1861     im = va_arg(ap, jsdouble);
1862     if (!JS_NewNumberValue(cx, re, &vp[0]))
1863     return JS_FALSE;
1864     if (!JS_NewNumberValue(cx, im, &vp[1]))
1865     return JS_FALSE;
1866     }
1867     *vpp = vp + 2;
1868     *app = ap;
1869     printf("leaving ZZ_formatter");
1870     return JS_TRUE;
1871     }
1872    
1873     static JSBool
1874     ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1875     {
1876     JSBool b = JS_FALSE;
1877     jschar c = 0;
1878     int32 i = 0, j = 0;
1879     uint32 u = 0;
1880     jsdouble d = 0, I = 0, re = 0, im = 0;
1881     char *s = NULL;
1882     JSString *str = NULL;
1883     jschar *w = NULL;
1884     JSObject *obj2 = NULL;
1885     JSFunction *fun = NULL;
1886     jsval v = JSVAL_VOID;
1887     JSBool ok;
1888    
1889     if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter))
1890     return JS_FALSE;;
1891     ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*",
1892     &b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2,
1893     &fun, &v, &re, &im);
1894     JS_RemoveArgumentFormatter(cx, "ZZ");
1895     if (!ok)
1896     return JS_FALSE;
1897     fprintf(gOutFile,
1898     "b %u, c %x (%c), i %ld, u %lu, j %ld\n",
1899     b, c, (char)c, i, u, j);
1900     fprintf(gOutFile,
1901     "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n"
1902     "v %s, re %g, im %g\n",
1903     d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w),
1904     JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj2))),
1905     fun ? JS_GetStringBytes(JS_DecompileFunction(cx, fun, 4)) : "",
1906     JS_GetStringBytes(JS_ValueToString(cx, v)), re, im);
1907     return JS_TRUE;
1908     }
1909     #endif
1910    
1911     static JSBool
1912     BuildDate(JSContext *cx, uintN argc, jsval *vp)
1913     {
1914     char version[20] = "\n";
1915     #if JS_VERSION < 150
1916     sprintf(version, " for version %d\n", JS_VERSION);
1917     #endif
1918     fprintf(gOutFile, "built on %s at %s%s", __DATE__, __TIME__, version);
1919     *vp = JSVAL_VOID;
1920     return JS_TRUE;
1921     }
1922    
1923     static JSBool
1924     Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1925     {
1926     if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj))
1927     return JS_FALSE;
1928     JS_ClearScope(cx, obj);
1929     return JS_TRUE;
1930     }
1931    
1932     static JSBool
1933     Intern(JSContext *cx, uintN argc, jsval *vp)
1934     {
1935     JSString *str;
1936    
1937     str = JS_ValueToString(cx, argc == 0 ? JSVAL_VOID : vp[2]);
1938     if (!str)
1939     return JS_FALSE;
1940     if (!JS_InternUCStringN(cx, JS_GetStringChars(str),
1941     JS_GetStringLength(str))) {
1942     return JS_FALSE;
1943     }
1944     *vp = JSVAL_VOID;
1945     return JS_TRUE;
1946     }
1947    
1948     static JSBool
1949     Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1950     {
1951     JSFunction *fun;
1952     JSObject *funobj, *parent, *clone;
1953    
1954     fun = JS_ValueToFunction(cx, argv[0]);
1955     if (!fun)
1956     return JS_FALSE;
1957     funobj = JS_GetFunctionObject(fun);
1958     if (argc > 1) {
1959     if (!JS_ValueToObject(cx, argv[1], &parent))
1960     return JS_FALSE;
1961     } else {
1962     parent = JS_GetParent(cx, funobj);
1963     }
1964     clone = JS_CloneFunctionObject(cx, funobj, parent);
1965     if (!clone)
1966     return JS_FALSE;
1967     *rval = OBJECT_TO_JSVAL(clone);
1968     return JS_TRUE;
1969     }
1970    
1971     static JSBool
1972     Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1973     {
1974     JSObject *target;
1975     JSBool deep = JS_FALSE;
1976    
1977     if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
1978     return JS_FALSE;
1979     if (!target)
1980     return JS_TRUE;
1981     return JS_SealObject(cx, target, deep);
1982     }
1983    
1984     static JSBool
1985     GetPDA(JSContext *cx, uintN argc, jsval *vp)
1986     {
1987     JSObject *vobj, *aobj, *pdobj;
1988     JSBool ok;
1989     JSPropertyDescArray pda;
1990     JSPropertyDesc *pd;
1991     uint32 i;
1992     jsval v;
1993    
1994     if (!JS_ValueToObject(cx, argc == 0 ? JSVAL_VOID : vp[2], &vobj))
1995     return JS_FALSE;
1996     if (!vobj)
1997     return JS_TRUE;
1998    
1999     aobj = JS_NewArrayObject(cx, 0, NULL);
2000     if (!aobj)
2001     return JS_FALSE;
2002     *vp = OBJECT_TO_JSVAL(aobj);
2003    
2004     ok = JS_GetPropertyDescArray(cx, vobj, &pda);
2005     if (!ok)
2006     return JS_FALSE;
2007     pd = pda.array;
2008     for (i = 0; i < pda.length; i++) {
2009     pdobj = JS_NewObject(cx, NULL, NULL, NULL);
2010     if (!pdobj) {
2011     ok = JS_FALSE;
2012     break;
2013     }
2014    
2015     /* Protect pdobj from GC by setting it as an element of aobj now */
2016     v = OBJECT_TO_JSVAL(pdobj);
2017     ok = JS_SetElement(cx, aobj, i, &v);
2018     if (!ok)
2019     break;
2020    
2021     ok = JS_SetProperty(cx, pdobj, "id", &pd->id) &&
2022     JS_SetProperty(cx, pdobj, "value", &pd->value) &&
2023     (v = INT_TO_JSVAL(pd->flags),
2024     JS_SetProperty(cx, pdobj, "flags", &v)) &&
2025     (v = INT_TO_JSVAL(pd->slot),
2026     JS_SetProperty(cx, pdobj, "slot", &v)) &&
2027     JS_SetProperty(cx, pdobj, "alias", &pd->alias);
2028     if (!ok)
2029     break;
2030     }
2031     JS_PutPropertyDescArray(cx, &pda);
2032     return ok;
2033     }
2034    
2035     static JSBool
2036     GetSLX(JSContext *cx, uintN argc, jsval *vp)
2037     {
2038     JSScript *script;
2039    
2040     script = ValueToScript(cx, argc == 0 ? JSVAL_VOID : vp[2]);
2041     if (!script)
2042     return JS_FALSE;
2043     *vp = INT_TO_JSVAL(js_GetScriptLineExtent(script));
2044     return JS_TRUE;
2045     }
2046    
2047     static JSBool
2048     ToInt32(JSContext *cx, uintN argc, jsval *vp)
2049     {
2050     int32 i;
2051    
2052     if (!JS_ValueToInt32(cx, argc == 0 ? JSVAL_VOID : vp[2], &i))
2053     return JS_FALSE;
2054     return JS_NewNumberValue(cx, i, vp);
2055     }
2056    
2057     static JSBool
2058     StringsAreUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2059     jsval *rval)
2060     {
2061     *rval = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE;
2062     return JS_TRUE;
2063     }
2064    
2065     static JSBool
2066     StackQuota(JSContext *cx, uintN argc, jsval *vp)
2067     {
2068     uint32 n;
2069    
2070     if (argc == 0)
2071     return JS_NewNumberValue(cx, (double) gScriptStackQuota, vp);
2072     if (!JS_ValueToECMAUint32(cx, JS_ARGV(cx, vp)[0], &n))
2073     return JS_FALSE;
2074     gScriptStackQuota = n;
2075     JS_SetScriptStackQuota(cx, gScriptStackQuota);
2076     JS_SET_RVAL(cx, vp, JSVAL_VOID);
2077     return JS_TRUE;
2078     }
2079    
2080     static const char* badUTF8 = "...\xC0...";
2081     static const char* bigUTF8 = "...\xFB\xBF\xBF\xBF\xBF...";
2082     static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 };
2083    
2084     static JSBool
2085     TestUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2086     {
2087     int32 mode = 1;
2088     jschar chars[20];
2089     size_t charsLength = 5;
2090     char bytes[20];
2091     size_t bytesLength = 20;
2092     if (argc && !JS_ValueToInt32(cx, *argv, &mode))
2093     return JS_FALSE;
2094    
2095     /* The following throw errors if compiled with UTF-8. */
2096     switch (mode) {
2097     /* mode 1: malformed UTF-8 string. */
2098     case 1:
2099     JS_NewStringCopyZ(cx, badUTF8);
2100     break;
2101     /* mode 2: big UTF-8 character. */
2102     case 2:
2103     JS_NewStringCopyZ(cx, bigUTF8);
2104     break;
2105     /* mode 3: bad surrogate character. */
2106     case 3:
2107     JS_EncodeCharacters(cx, badSurrogate, 6, bytes, &bytesLength);
2108     break;
2109     /* mode 4: use a too small buffer. */
2110     case 4:
2111     JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength);
2112     break;
2113     default:
2114     JS_ReportError(cx, "invalid mode parameter");
2115     return JS_FALSE;
2116     }
2117     return !JS_IsExceptionPending (cx);
2118     }
2119    
2120     static JSBool
2121     ThrowError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2122     {
2123     JS_ReportError(cx, "This is an error");
2124     return JS_FALSE;
2125     }
2126    
2127     #define LAZY_STANDARD_CLASSES
2128    
2129     /* A class for easily testing the inner/outer object callbacks. */
2130     typedef struct ComplexObject {
2131     JSBool isInner;
2132     JSBool frozen;
2133     JSObject *inner;
2134     JSObject *outer;
2135     } ComplexObject;
2136    
2137     static JSObject *
2138     split_create_outer(JSContext *cx);
2139    
2140     static JSObject *
2141     split_create_inner(JSContext *cx, JSObject *outer);
2142    
2143     static ComplexObject *
2144     split_get_private(JSContext *cx, JSObject *obj);
2145    
2146     static JSBool
2147     split_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2148     {
2149     ComplexObject *cpx;
2150     jsid asId;
2151    
2152     cpx = split_get_private(cx, obj);
2153     if (!cpx)
2154     return JS_TRUE;
2155     if (!cpx->isInner && cpx->inner) {
2156     /* Make sure to define this property on the inner object. */
2157     if (!JS_ValueToId(cx, *vp, &asId))
2158     return JS_FALSE;
2159     return OBJ_DEFINE_PROPERTY(cx, cpx->inner, asId, *vp, NULL, NULL,
2160     JSPROP_ENUMERATE, NULL);
2161     }
2162     return JS_TRUE;
2163     }
2164    
2165     static JSBool
2166     split_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2167     {
2168     ComplexObject *cpx;
2169    
2170     cpx = split_get_private(cx, obj);
2171     if (!cpx)
2172     return JS_TRUE;
2173     if (!cpx->isInner && cpx->inner) {
2174     if (JSVAL_IS_STRING(id)) {
2175     JSString *str;
2176    
2177     str = JSVAL_TO_STRING(id);
2178     return JS_GetUCProperty(cx, cpx->inner, JS_GetStringChars(str),
2179     JS_GetStringLength(str), vp);
2180     }
2181     if (JSVAL_IS_INT(id))
2182     return JS_GetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp);
2183     return JS_TRUE;
2184     }
2185    
2186     return JS_TRUE;
2187     }
2188    
2189     static JSBool
2190     split_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2191     {
2192     ComplexObject *cpx;
2193    
2194     cpx = split_get_private(cx, obj);
2195     if (!cpx)
2196     return JS_TRUE;
2197     if (!cpx->isInner && cpx->inner) {
2198     if (JSVAL_IS_STRING(id)) {
2199     JSString *str;
2200    
2201     str = JSVAL_TO_STRING(id);
2202     return JS_SetUCProperty(cx, cpx->inner, JS_GetStringChars(str),
2203     JS_GetStringLength(str), vp);
2204     }
2205     if (JSVAL_IS_INT(id))
2206     return JS_SetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp);
2207     return JS_TRUE;
2208     }
2209    
2210     return JS_TRUE;
2211     }
2212    
2213     static JSBool
2214     split_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2215     {
2216     ComplexObject *cpx;
2217     jsid asId;
2218    
2219     cpx = split_get_private(cx, obj);
2220     if (!cpx)
2221     return JS_TRUE;
2222     if (!cpx->isInner && cpx->inner) {
2223     /* Make sure to define this property on the inner object. */
2224     if (!JS_ValueToId(cx, *vp, &asId))
2225     return JS_FALSE;
2226     return OBJ_DELETE_PROPERTY(cx, cpx->inner, asId, vp);
2227     }
2228     return JS_TRUE;
2229     }
2230    
2231     static JSBool
2232     split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
2233     jsval *statep, jsid *idp)
2234     {
2235     ComplexObject *cpx;
2236     JSObject *iterator;
2237    
2238     switch (enum_op) {
2239     case JSENUMERATE_INIT:
2240     cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
2241    
2242     if (!cpx->isInner && cpx->inner)
2243     obj = cpx->inner;
2244    
2245     iterator = JS_NewPropertyIterator(cx, obj);
2246     if (!iterator)
2247     return JS_FALSE;
2248    
2249     *statep = OBJECT_TO_JSVAL(iterator);
2250     if (idp)
2251     *idp = JSVAL_ZERO;
2252     break;
2253    
2254     case JSENUMERATE_NEXT:
2255     iterator = (JSObject*)JSVAL_TO_OBJECT(*statep);
2256     if (!JS_NextProperty(cx, iterator, idp))
2257     return JS_FALSE;
2258    
2259     if (!JSVAL_IS_VOID(*idp))
2260     break;
2261     /* Fall through. */
2262    
2263     case JSENUMERATE_DESTROY:
2264     /* Let GC at our iterator object. */
2265     *statep = JSVAL_NULL;
2266     break;
2267     }
2268    
2269     return JS_TRUE;
2270     }
2271    
2272     static JSBool
2273     split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
2274     JSObject **objp)
2275     {
2276     ComplexObject *cpx;
2277    
2278     cpx = split_get_private(cx, obj);
2279     if (!cpx)
2280     return JS_TRUE;
2281     if (!cpx->isInner && cpx->inner) {
2282     jsid asId;
2283     JSProperty *prop;
2284    
2285     if (!JS_ValueToId(cx, id, &asId))
2286     return JS_FALSE;
2287    
2288     if (!OBJ_LOOKUP_PROPERTY(cx, cpx->inner, asId, objp, &prop))
2289     return JS_FALSE;
2290     if (prop)
2291     OBJ_DROP_PROPERTY(cx, cpx->inner, prop);
2292    
2293     return JS_TRUE;
2294     }
2295    
2296     #ifdef LAZY_STANDARD_CLASSES
2297     if (!(flags & JSRESOLVE_ASSIGNING)) {
2298     JSBool resolved;
2299    
2300     if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
2301     return JS_FALSE;
2302    
2303     if (resolved) {
2304     *objp = obj;
2305     return JS_TRUE;
2306     }
2307     }
2308     #endif
2309    
2310     /* XXX For additional realism, let's resolve some random property here. */
2311     return JS_TRUE;
2312     }
2313    
2314     static void
2315     split_finalize(JSContext *cx, JSObject *obj)
2316     {
2317     JS_free(cx, JS_GetPrivate(cx, obj));
2318     }
2319    
2320     static uint32
2321     split_mark(JSContext *cx, JSObject *obj, void *arg)
2322     {
2323     ComplexObject *cpx;
2324    
2325     cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
2326    
2327     if (!cpx->isInner && cpx->inner) {
2328     /* Mark the inner object. */
2329     JS_MarkGCThing(cx, cpx->inner, "ComplexObject.inner", arg);
2330     }
2331    
2332     return 0;
2333     }
2334    
2335     static JSObject *
2336     split_outerObject(JSContext *cx, JSObject *obj)
2337     {
2338     ComplexObject *cpx;
2339    
2340     cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
2341     return cpx->isInner ? cpx->outer : obj;
2342     }
2343    
2344     static JSObject *
2345     split_innerObject(JSContext *cx, JSObject *obj)
2346     {
2347     ComplexObject *cpx;
2348    
2349     cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
2350     if (cpx->frozen) {
2351     JS_ASSERT(!cpx->isInner);
2352     return obj;
2353     }
2354     return !cpx->isInner ? cpx->inner : obj;
2355     }
2356    
2357     static JSExtendedClass split_global_class = {
2358     {"split_global",
2359     JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE |
2360     JSCLASS_GLOBAL_FLAGS | JSCLASS_IS_EXTENDED,
2361     split_addProperty, split_delProperty,
2362     split_getProperty, split_setProperty,
2363     (JSEnumerateOp)split_enumerate,
2364     (JSResolveOp)split_resolve,
2365     JS_ConvertStub, split_finalize,
2366     NULL, NULL, NULL, NULL, NULL, NULL,
2367     split_mark, NULL},
2368     NULL, split_outerObject, split_innerObject,
2369     NULL, NULL, NULL, NULL, NULL
2370     };
2371    
2372     JSObject *
2373     split_create_outer(JSContext *cx)
2374     {
2375     ComplexObject *cpx;
2376     JSObject *obj;
2377    
2378     cpx = (ComplexObject *) JS_malloc(cx, sizeof *obj);
2379     if (!cpx)
2380     return NULL;
2381     cpx->isInner = JS_FALSE;
2382     cpx->frozen = JS_TRUE;
2383     cpx->inner = NULL;
2384     cpx->outer = NULL;
2385    
2386     obj = JS_NewObject(cx, &split_global_class.base, NULL, NULL);
2387     if (!obj || !JS_SetParent(cx, obj, NULL)) {
2388     JS_free(cx, cpx);
2389     return NULL;
2390     }
2391    
2392     if (!JS_SetPrivate(cx, obj, cpx)) {
2393     JS_free(cx, cpx);
2394     return NULL;
2395     }
2396    
2397     return obj;
2398     }
2399    
2400     static JSObject *
2401     split_create_inner(JSContext *cx, JSObject *outer)
2402     {
2403     ComplexObject *cpx, *outercpx;
2404     JSObject *obj;
2405    
2406     JS_ASSERT(JS_GET_CLASS(cx, outer) == &split_global_class.base);
2407    
2408     cpx = (ComplexObject *) JS_malloc(cx, sizeof *cpx);
2409     if (!cpx)
2410     return NULL;
2411     cpx->isInner = JS_TRUE;
2412     cpx->frozen = JS_FALSE;
2413     cpx->inner = NULL;
2414     cpx->outer = outer;
2415    
2416     obj = JS_NewObject(cx, &split_global_class.base, NULL, NULL);
2417     if (!obj || !JS_SetParent(cx, obj, NULL) || !JS_SetPrivate(cx, obj, cpx)) {
2418     JS_free(cx, cpx);
2419     return NULL;
2420     }
2421    
2422     outercpx = (ComplexObject *) JS_GetPrivate(cx, outer);
2423     outercpx->inner = obj;
2424     outercpx->frozen = JS_FALSE;
2425    
2426     return obj;
2427     }
2428    
2429     static ComplexObject *
2430     split_get_private(JSContext *cx, JSObject *obj)
2431     {
2432     do {
2433     if (JS_GET_CLASS(cx, obj) == &split_global_class.base)
2434     return (ComplexObject *) JS_GetPrivate(cx, obj);
2435     obj = JS_GetParent(cx, obj);
2436     } while (obj);
2437    
2438     return NULL;
2439     }
2440    
2441     static JSBool
2442     sandbox_enumerate(JSContext *cx, JSObject *obj)
2443     {
2444     jsval v;
2445     JSBool b;
2446    
2447     if (!JS_GetProperty(cx, obj, "lazy", &v) || !JS_ValueToBoolean(cx, v, &b))
2448     return JS_FALSE;
2449     return !b || JS_EnumerateStandardClasses(cx, obj);
2450     }
2451    
2452     static JSBool
2453     sandbox_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
2454     JSObject **objp)
2455     {
2456     jsval v;
2457     JSBool b, resolved;
2458    
2459     if (!JS_GetProperty(cx, obj, "lazy", &v) || !JS_ValueToBoolean(cx, v, &b))
2460     return JS_FALSE;
2461     if (b && (flags & JSRESOLVE_ASSIGNING) == 0) {
2462     if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
2463     return JS_FALSE;
2464     if (resolved) {
2465     *objp = obj;
2466     return JS_TRUE;
2467     }
2468     }
2469     *objp = NULL;
2470     return JS_TRUE;
2471     }
2472    
2473     static JSClass sandbox_class = {
2474     "sandbox",
2475     JSCLASS_NEW_RESOLVE,
2476     JS_PropertyStub, JS_PropertyStub,
2477     JS_PropertyStub, JS_PropertyStub,
2478     sandbox_enumerate, (JSResolveOp)sandbox_resolve,
2479     JS_ConvertStub, JS_FinalizeStub,
2480     JSCLASS_NO_OPTIONAL_MEMBERS
2481     };
2482    
2483     static JSBool
2484     EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2485     jsval *rval)
2486     {
2487     JSString *str;
2488     JSObject *sobj;
2489     JSContext *scx;
2490     const jschar *src;
2491     size_t srclen;
2492     JSBool lazy, ok;
2493     jsval v;
2494     JSStackFrame *fp;
2495    
2496     sobj = NULL;
2497     if (!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sobj))
2498     return JS_FALSE;
2499    
2500     scx = JS_NewContext(JS_GetRuntime(cx), gStackChunkSize);
2501     if (!scx) {
2502     JS_ReportOutOfMemory(cx);
2503     return JS_FALSE;
2504     }
2505    
2506     #ifdef JS_THREADSAFE
2507     JS_BeginRequest(scx);
2508     #endif
2509     src = JS_GetStringChars(str);
2510     srclen = JS_GetStringLength(str);
2511     lazy = JS_FALSE;
2512     if (srclen == 4 &&
2513     src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') {
2514     lazy = JS_TRUE;
2515     srclen = 0;
2516     }
2517    
2518     if (!sobj) {
2519     sobj = JS_NewObject(scx, &sandbox_class, NULL, NULL);
2520     if (!sobj || (!lazy && !JS_InitStandardClasses(scx, sobj))) {
2521     ok = JS_FALSE;
2522     goto out;
2523     }
2524     v = BOOLEAN_TO_JSVAL(lazy);
2525     ok = JS_SetProperty(cx, sobj, "lazy", &v);
2526     if (!ok)
2527     goto out;
2528     }
2529    
2530     if (srclen == 0) {
2531     *rval = OBJECT_TO_JSVAL(sobj);
2532     ok = JS_TRUE;
2533     } else {
2534     fp = JS_GetScriptedCaller(cx, NULL);
2535     JS_SetGlobalObject(scx, sobj);
2536     JS_ToggleOptions(scx, JSOPTION_DONT_REPORT_UNCAUGHT);
2537     ok = JS_EvaluateUCScript(scx, sobj, src, srclen,
2538     fp->script->filename,
2539     JS_PCToLineNumber(cx, fp->script,
2540     fp->regs->pc),
2541     rval);
2542     if (!ok) {
2543     if (JS_GetPendingException(scx, &v))
2544     JS_SetPendingException(cx, v);
2545     else
2546     JS_ReportOutOfMemory(cx);
2547     }
2548     }
2549    
2550     out:
2551     #ifdef JS_THREADSAFE
2552     JS_EndRequest(scx);
2553     #endif
2554     JS_DestroyContext(scx);
2555     return ok;
2556     }
2557    
2558 siliconforks 399 static int32 JS_FASTCALL
2559     ShapeOf_tn(JSObject *obj)
2560     {
2561     if (!obj)
2562     return 0;
2563     if (!OBJ_IS_NATIVE(obj))
2564     return -1;
2565     return OBJ_SHAPE(obj);
2566     }
2567    
2568     static JSBool
2569     ShapeOf(JSContext *cx, uintN argc, jsval *vp)
2570     {
2571     jsval v = JS_ARGV(cx, vp)[0];
2572     if (!JSVAL_IS_OBJECT(v)) {
2573     JS_ReportError(cx, "shapeOf: object expected");
2574