/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/js.cpp
C++ | 2422 lines | 2145 code | 178 blank | 99 comment | 272 complexity | cd90b6c90083454ce65be2119e7ba9a5 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
- /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=99:
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- /*
- * JS shell.
- */
- #include "jsstddef.h"
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <locale.h>
- #include "jstypes.h"
- #include "jsarena.h"
- #include "jsutil.h"
- #include "jsprf.h"
- #include "jsapi.h"
- #include "jsarray.h"
- #include "jsatom.h"
- #include "jsbuiltins.h"
- #include "jscntxt.h"
- #include "jsdbgapi.h"
- #include "jsemit.h"
- #include "jsfun.h"
- #include "jsgc.h"
- #include "jslock.h"
- #include "jsnum.h"
- #include "jsobj.h"
- #include "jsparse.h"
- #include "jsscope.h"
- #include "jsscript.h"
- #ifdef LIVECONNECT
- #include "jsjava.h"
- #endif
- #ifdef JSDEBUGGER
- #include "jsdebug.h"
- #ifdef JSDEBUGGER_JAVA_UI
- #include "jsdjava.h"
- #endif /* JSDEBUGGER_JAVA_UI */
- #ifdef JSDEBUGGER_C_UI
- #include "jsdb.h"
- #endif /* JSDEBUGGER_C_UI */
- #endif /* JSDEBUGGER */
- #ifdef XP_UNIX
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #endif
- #if defined(XP_WIN) || defined(XP_OS2)
- #include <io.h> /* for isatty() */
- #endif
- typedef enum JSShellExitCode {
- EXITCODE_RUNTIME_ERROR = 3,
- EXITCODE_FILE_NOT_FOUND = 4,
- EXITCODE_OUT_OF_MEMORY = 5
- } JSShellExitCode;
- size_t gStackChunkSize = 8192;
- /* Assume that we can not use more than 5e5 bytes of C stack by default. */
- static size_t gMaxStackSize = 500000;
- static jsuword gStackBase;
- static size_t gScriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
- static JSBool gEnableBranchCallback = JS_FALSE;
- static uint32 gBranchCount;
- static uint32 gBranchLimit;
- int gExitCode = 0;
- JSBool gQuitting = JS_FALSE;
- FILE *gErrFile = NULL;
- FILE *gOutFile = NULL;
- static JSBool reportWarnings = JS_TRUE;
- static JSBool compileOnly = JS_FALSE;
- typedef enum JSShellErrNum {
- #define MSG_DEF(name, number, count, exception, format) \
- name = number,
- #include "jsshell.msg"
- #undef MSG_DEF
- JSShellErr_Limit
- #undef MSGDEF
- } JSShellErrNum;
- static const JSErrorFormatString *
- my_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber);
- static JSObject *
- split_setup(JSContext *cx);
- #ifdef EDITLINE
- JS_BEGIN_EXTERN_C
- extern char *readline(const char *prompt);
- extern void add_history(char *line);
- JS_END_EXTERN_C
- #endif
- static JSBool
- GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
- #ifdef EDITLINE
- /*
- * Use readline only if file is stdin, because there's no way to specify
- * another handle. Are other filehandles interactive?
- */
- if (file == stdin) {
- char *linep = readline(prompt);
- if (!linep)
- return JS_FALSE;
- if (linep[0] != '\0')
- add_history(linep);
- strcpy(bufp, linep);
- JS_free(cx, linep);
- bufp += strlen(bufp);
- *bufp++ = '\n';
- *bufp = '\0';
- } else
- #endif
- {
- char line[256];
- fprintf(gOutFile, prompt);
- fflush(gOutFile);
- if (!fgets(line, sizeof line, file))
- return JS_FALSE;
- strcpy(bufp, line);
- }
- return JS_TRUE;
- }
- static JSBool
- my_BranchCallback(JSContext *cx, JSScript *script)
- {
- if (++gBranchCount == gBranchLimit) {
- if (script) {
- if (script->filename)
- fprintf(gErrFile, "%s:", script->filename);
- fprintf(gErrFile, "%u: script branch callback (%u callbacks)\n",
- script->lineno, gBranchLimit);
- } else {
- fprintf(gErrFile, "native branch callback (%u callbacks)\n",
- gBranchLimit);
- }
- gBranchCount = 0;
- return JS_FALSE;
- }
- #ifdef JS_THREADSAFE
- if ((gBranchCount & 0xff) == 1) {
- #endif
- if ((gBranchCount & 0x3fff) == 1)
- JS_MaybeGC(cx);
- #ifdef JS_THREADSAFE
- else
- JS_YieldRequest(cx);
- }
- #endif
- return JS_TRUE;
- }
- static void
- SetContextOptions(JSContext *cx)
- {
- jsuword stackLimit;
- if (gMaxStackSize == 0) {
- /*
- * Disable checking for stack overflow if limit is zero.
- */
- stackLimit = 0;
- } else {
- #if JS_STACK_GROWTH_DIRECTION > 0
- stackLimit = gStackBase + gMaxStackSize;
- #else
- stackLimit = gStackBase - gMaxStackSize;
- #endif
- }
- JS_SetThreadStackLimit(cx, stackLimit);
- JS_SetScriptStackQuota(cx, gScriptStackQuota);
- if (gEnableBranchCallback) {
- JS_SetBranchCallback(cx, my_BranchCallback);
- JS_ToggleOptions(cx, JSOPTION_NATIVE_BRANCH_CALLBACK);
- }
- }
- static void
- Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
- {
- JSBool ok, hitEOF;
- JSScript *script;
- jsval result;
- JSString *str;
- char buffer[4096];
- char *bufp;
- int lineno;
- int startline;
- FILE *file;
- uint32 oldopts;
- if (forceTTY || !filename || strcmp(filename, "-") == 0) {
- file = stdin;
- } else {
- file = fopen(filename, "r");
- if (!file) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
- JSSMSG_CANT_OPEN, filename, strerror(errno));
- gExitCode = EXITCODE_FILE_NOT_FOUND;
- return;
- }
- }
- SetContextOptions(cx);
- if (!forceTTY && !isatty(fileno(file))) {
- /*
- * It's not interactive - just execute it.
- *
- * Support the UNIX #! shell hack; gobble the first line if it starts
- * with '#'. TODO - this isn't quite compatible with sharp variables,
- * as a legal js program (using sharp variables) might start with '#'.
- * But that would require multi-character lookahead.
- */
- int ch = fgetc(file);
- if (ch == '#') {
- while((ch = fgetc(file)) != EOF) {
- if (ch == '\n' || ch == '\r')
- break;
- }
- }
- ungetc(ch, file);
- oldopts = JS_GetOptions(cx);
- JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
- script = JS_CompileFileHandle(cx, obj, filename, file);
- JS_SetOptions(cx, oldopts);
- if (script) {
- if (!compileOnly)
- (void)JS_ExecuteScript(cx, obj, script, NULL);
- JS_DestroyScript(cx, script);
- }
- if (file != stdin)
- fclose(file);
- return;
- }
- /* It's an interactive filehandle; drop into read-eval-print loop. */
- lineno = 1;
- hitEOF = JS_FALSE;
- do {
- bufp = buffer;
- *bufp = '\0';
- /*
- * Accumulate lines until we get a 'compilable unit' - one that either
- * generates an error (before running out of source) or that compiles
- * cleanly. This should be whenever we get a complete statement that
- * coincides with the end of a line.
- */
- startline = lineno;
- do {
- if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
- hitEOF = JS_TRUE;
- break;
- }
- bufp += strlen(bufp);
- lineno++;
- } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
- /* Clear any pending exception from previous failed compiles. */
- JS_ClearPendingException(cx);
- script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein",
- startline);
- if (script) {
- if (!compileOnly) {
- ok = JS_ExecuteScript(cx, obj, script, &result);
- if (ok && !JSVAL_IS_VOID(result)) {
- str = JS_ValueToString(cx, result);
- if (str)
- fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
- else
- ok = JS_FALSE;
- }
- }
- JS_DestroyScript(cx, script);
- }
- } while (!hitEOF && !gQuitting);
- fprintf(gOutFile, "\n");
- if (file != stdin)
- fclose(file);
- return;
- }
- static int
- usage(void)
- {
- fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
- fprintf(gErrFile, "usage: js [-zKPswWxCi] [-b branchlimit] [-c stackchunksize] [-o option] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] "
- #ifdef JS_GC_ZEAL
- "[-Z gczeal] "
- #endif
- "[scriptfile] [scriptarg...]\n");
- return 2;
- }
- static struct {
- const char *name;
- uint32 flag;
- } js_options[] = {
- {"strict", JSOPTION_STRICT},
- {"werror", JSOPTION_WERROR},
- {"atline", JSOPTION_ATLINE},
- {"xml", JSOPTION_XML},
- {"relimit", JSOPTION_RELIMIT},
- {"anonfunfix", JSOPTION_ANONFUNFIX},
- {"jit", JSOPTION_JIT},
- {NULL, 0}
- };
- extern JSClass global_class;
- static int
- ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
- {
- int i, j, length;
- JSObject *argsObj;
- char *filename = NULL;
- JSBool isInteractive = JS_TRUE;
- JSBool forceTTY = JS_FALSE;
- /*
- * Scan past all optional arguments so we can create the arguments object
- * before processing any -f options, which must interleave properly with
- * -v and -w options. This requires two passes, and without getopt, we'll
- * have to keep the option logic here and in the second for loop in sync.
- */
- for (i = 0; i < argc; i++) {
- if (argv[i][0] != '-' || argv[i][1] == '\0') {
- ++i;
- break;
- }
- switch (argv[i][1]) {
- case 'b':
- case 'c':
- case 'f':
- case 'e':
- case 'v':
- case 'S':
- #ifdef JS_GC_ZEAL
- case 'Z':
- #endif
- ++i;
- break;
- default:;
- }
- }
- /*
- * Create arguments early and define it to root it, so it's safe from any
- * GC calls nested below, and so it is available to -f <file> arguments.
- */
- argsObj = JS_NewArrayObject(cx, 0, NULL);
- if (!argsObj)
- return 1;
- if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
- NULL, NULL, 0)) {
- return 1;
- }
- length = argc - i;
- for (j = 0; j < length; j++) {
- JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
- if (!str)
- return 1;
- if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str),
- NULL, NULL, JSPROP_ENUMERATE)) {
- return 1;
- }
- }
- for (i = 0; i < argc; i++) {
- if (argv[i][0] != '-' || argv[i][1] == '\0') {
- filename = argv[i++];
- isInteractive = JS_FALSE;
- break;
- }
- switch (argv[i][1]) {
- case 'v':
- if (++i == argc)
- return usage();
- JS_SetVersion(cx, (JSVersion) atoi(argv[i]));
- break;
- #ifdef JS_GC_ZEAL
- case 'Z':
- if (++i == argc)
- return usage();
- JS_SetGCZeal(cx, atoi(argv[i]));
- break;
- #endif
- case 'w':
- reportWarnings = JS_TRUE;
- break;
- case 'W':
- reportWarnings = JS_FALSE;
- break;
- case 's':
- JS_ToggleOptions(cx, JSOPTION_STRICT);
- break;
- case 'E':
- JS_ToggleOptions(cx, JSOPTION_RELIMIT);
- break;
- case 'x':
- JS_ToggleOptions(cx, JSOPTION_XML);
- break;
- case 'j':
- JS_ToggleOptions(cx, JSOPTION_JIT);
- #if defined(JS_TRACER) && defined(DEBUG)
- extern struct JSClass jitstats_class;
- extern void js_InitJITStatsClass(JSContext *cx, JSObject *glob);
- js_InitJITStatsClass(cx, JS_GetGlobalObject(cx));
- JS_DefineObject(cx, JS_GetGlobalObject(cx), "tracemonkey",
- &jitstats_class, NULL, 0);
- #endif
- break;
-
- case 'o':
- if (++i == argc)
- return usage();
- for (j = 0; js_options[j].name; ++j) {
- if (strcmp(js_options[j].name, argv[i]) == 0) {
- JS_ToggleOptions(cx, js_options[j].flag);
- break;
- }
- }
- break;
- case 'P':
- if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) {
- JSObject *gobj;
- if (!JS_SealObject(cx, obj, JS_TRUE))
- return JS_FALSE;
- gobj = JS_NewObject(cx, &global_class, NULL, NULL);
- if (!gobj)
- return JS_FALSE;
- if (!JS_SetPrototype(cx, gobj, obj))
- return JS_FALSE;
- JS_SetParent(cx, gobj, NULL);
- JS_SetGlobalObject(cx, gobj);
- obj = gobj;
- }
- break;
- case 'b':
- gBranchLimit = atoi(argv[++i]);
- gEnableBranchCallback = (gBranchLimit != 0);
- break;
- case 'c':
- /* set stack chunk size */
- gStackChunkSize = atoi(argv[++i]);
- break;
- case 'f':
- if (++i == argc)
- return usage();
- Process(cx, obj, argv[i], JS_FALSE);
- /*
- * XXX: js -f foo.js should interpret foo.js and then
- * drop into interactive mode, but that breaks the test
- * harness. Just execute foo.js for now.
- */
- isInteractive = JS_FALSE;
- break;
- case 'e':
- {
- jsval rval;
- if (++i == argc)
- return usage();
- /* Pass a filename of -e to imitate PERL */
- JS_EvaluateScript(cx, obj, argv[i], strlen(argv[i]),
- "-e", 1, &rval);
- isInteractive = JS_FALSE;
- break;
- }
- case 'C':
- compileOnly = JS_TRUE;
- isInteractive = JS_FALSE;
- break;
- case 'i':
- isInteractive = forceTTY = JS_TRUE;
- break;
- case 'S':
- if (++i == argc)
- return usage();
- /* Set maximum stack size. */
- gMaxStackSize = atoi(argv[i]);
- break;
- case 'z':
- obj = split_setup(cx);
- if (!obj)
- return gExitCode;
- break;
- #ifdef MOZ_SHARK
- case 'k':
- JS_ConnectShark();
- break;
- #endif
- default:
- return usage();
- }
- }
- if (filename || isInteractive)
- Process(cx, obj, filename, forceTTY);
- return gExitCode;
- }
- static JSBool
- Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- if (argc > 0 && JSVAL_IS_INT(argv[0]))
- *rval = INT_TO_JSVAL(JS_SetVersion(cx, (JSVersion) JSVAL_TO_INT(argv[0])));
- else
- *rval = INT_TO_JSVAL(JS_GetVersion(cx));
- return JS_TRUE;
- }
- static JSBool
- Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- uint32 optset, flag;
- uintN i, j, found;
- JSString *str;
- const char *opt;
- char *names;
- optset = 0;
- for (i = 0; i < argc; i++) {
- str = JS_ValueToString(cx, argv[i]);
- if (!str)
- return JS_FALSE;
- opt = JS_GetStringBytes(str);
- for (j = 0; js_options[j].name; j++) {
- if (strcmp(js_options[j].name, opt) == 0) {
- optset |= js_options[j].flag;
- break;
- }
- }
- }
- optset = JS_ToggleOptions(cx, optset);
- names = NULL;
- found = 0;
- while (optset != 0) {
- flag = optset;
- optset &= optset - 1;
- flag &= ~optset;
- for (j = 0; js_options[j].name; j++) {
- if (js_options[j].flag == flag) {
- names = JS_sprintf_append(names, "%s%s",
- names ? "," : "", js_options[j].name);
- found++;
- break;
- }
- }
- }
- if (!found)
- names = strdup("");
- if (!names) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
- str = JS_NewString(cx, names, strlen(names));
- if (!str) {
- free(names);
- return JS_FALSE;
- }
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
- static JSBool
- Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- uintN i;
- JSString *str;
- const char *filename;
- JSScript *script;
- JSBool ok;
- uint32 oldopts;
- for (i = 0; i < argc; i++) {
- str = JS_ValueToString(cx, argv[i]);
- if (!str)
- return JS_FALSE;
- argv[i] = STRING_TO_JSVAL(str);
- filename = JS_GetStringBytes(str);
- errno = 0;
- oldopts = JS_GetOptions(cx);
- JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
- script = JS_CompileFile(cx, obj, filename);
- JS_SetOptions(cx, oldopts);
- if (!script) {
- ok = JS_FALSE;
- } else {
- ok = !compileOnly
- ? JS_ExecuteScript(cx, obj, script, NULL)
- : JS_TRUE;
- JS_DestroyScript(cx, script);
- }
- if (!ok)
- return JS_FALSE;
- }
- return JS_TRUE;
- }
- /*
- * function readline()
- * Provides a hook for scripts to read a line from stdin.
- */
- static JSBool
- ReadLine(JSContext *cx, uintN argc, jsval *vp)
- {
- #define BUFSIZE 256
- FILE *from;
- char *buf, *tmp;
- size_t bufsize, buflength, gotlength;
- JSBool sawNewline;
- JSString *str;
- from = stdin;
- buflength = 0;
- bufsize = BUFSIZE;
- buf = (char *) JS_malloc(cx, bufsize);
- if (!buf)
- return JS_FALSE;
- sawNewline = JS_FALSE;
- while ((gotlength =
- js_fgets(buf + buflength, bufsize - buflength, from)) > 0) {
- buflength += gotlength;
- /* Are we done? */
- if (buf[buflength - 1] == '\n') {
- buf[buflength - 1] = '\0';
- sawNewline = JS_TRUE;
- break;
- } else if (buflength < bufsize - 1) {
- break;
- }
- /* Else, grow our buffer for another pass. */
- bufsize *= 2;
- if (bufsize > buflength) {
- tmp = (char *) JS_realloc(cx, buf, bufsize);
- } else {
- JS_ReportOutOfMemory(cx);
- tmp = NULL;
- }
- if (!tmp) {
- JS_free(cx, buf);
- return JS_FALSE;
- }
- buf = tmp;
- }
- /* Treat the empty string specially. */
- if (buflength == 0) {
- *vp = feof(from) ? JSVAL_NULL : JS_GetEmptyStringValue(cx);
- JS_free(cx, buf);
- return JS_TRUE;
- }
- /* Shrink the buffer to the real size. */
- tmp = (char *) JS_realloc(cx, buf, buflength);
- if (!tmp) {
- JS_free(cx, buf);
- return JS_FALSE;
- }
- buf = tmp;
- /*
- * Turn buf into a JSString. Note that buflength includes the trailing null
- * character.
- */
- str = JS_NewString(cx, buf, sawNewline ? buflength - 1 : buflength);
- if (!str) {
- JS_free(cx, buf);
- return JS_FALSE;
- }
- *vp = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
- #ifdef JS_TRACER
- static jsval JS_FASTCALL
- Print_tn(JSContext *cx, JSString *str)
- {
- char *bytes = JS_EncodeString(cx, str);
- if (!bytes)
- return JSVAL_ERROR_COOKIE;
- fprintf(gOutFile, "%s\n", bytes);
- JS_free(cx, bytes);
- fflush(gOutFile);
- return JSVAL_VOID;
- }
- #endif
- static JSBool
- Print(JSContext *cx, uintN argc, jsval *vp)
- {
- jsval *argv;
- uintN i;
- JSString *str;
- char *bytes;
- argv = JS_ARGV(cx, vp);
- for (i = 0; i < argc; i++) {
- str = JS_ValueToString(cx, argv[i]);
- if (!str)
- return JS_FALSE;
- bytes = JS_EncodeString(cx, str);
- if (!bytes)
- return JS_FALSE;
- fprintf(gOutFile, "%s%s", i ? " " : "", bytes);
- JS_free(cx, bytes);
- }
- fputc('\n', gOutFile);
- fflush(gOutFile);
- JS_SET_RVAL(cx, vp, JSVAL_VOID);
- return JS_TRUE;
- }
- static JSBool
- Help(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
- static JSBool
- Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- #ifdef LIVECONNECT
- JSJ_SimpleShutdown();
- #endif
- JS_ConvertArguments(cx, argc, argv,"/ i", &gExitCode);
- gQuitting = JS_TRUE;
- return JS_FALSE;
- }
- static JSBool
- GC(JSContext *cx, uintN argc, jsval *vp)
- {
- JSRuntime *rt;
- uint32 preBytes;
- rt = cx->runtime;
- preBytes = rt->gcBytes;
- JS_GC(cx);
- fprintf(gOutFile, "before %lu, after %lu, break %08lx\n",
- (unsigned long)preBytes, (unsigned long)rt->gcBytes,
- #ifdef XP_UNIX
- (unsigned long)sbrk(0)
- #else
- 0
- #endif
- );
- #ifdef JS_GCMETER
- js_DumpGCStats(rt, stdout);
- #endif
- *vp = JSVAL_VOID;
- return JS_TRUE;
- }
- static JSBool
- GCParameter(JSContext *cx, uintN argc, jsval *vp)
- {
- JSString *str;
- const char *paramName;
- JSGCParamKey param;
- uint32 value;
- if (argc == 0) {
- str = JS_ValueToString(cx, JSVAL_VOID);
- JS_ASSERT(str);
- } else {
- str = JS_ValueToString(cx, vp[2]);
- if (!str)
- return JS_FALSE;
- vp[2] = STRING_TO_JSVAL(str);
- }
- paramName = JS_GetStringBytes(str);
- if (!paramName)
- return JS_FALSE;
- if (strcmp(paramName, "maxBytes") == 0) {
- param = JSGC_MAX_BYTES;
- } else if (strcmp(paramName, "maxMallocBytes") == 0) {
- param = JSGC_MAX_MALLOC_BYTES;
- } else {
- JS_ReportError(cx,
- "the first argument argument must be either maxBytes "
- "or maxMallocBytes");
- return JS_FALSE;
- }
- if (!JS_ValueToECMAUint32(cx, argc < 2 ? JSVAL_VOID : vp[3], &value))
- return JS_FALSE;
- if (value == 0) {
- JS_ReportError(cx,
- "the second argument must be convertable to uint32 with "
- "non-zero value");
- return JS_FALSE;
- }
- JS_SetGCParameter(cx->runtime, param, value);
- *vp = JSVAL_VOID;
- return JS_TRUE;
- }
- #ifdef JS_GC_ZEAL
- static JSBool
- GCZeal(JSContext *cx, uintN argc, jsval *vp)
- {
- uint32 zeal;
- if (!JS_ValueToECMAUint32(cx, argc == 0 ? JSVAL_VOID : vp[2], &zeal))
- return JS_FALSE;
- JS_SetGCZeal(cx, (uint8)zeal);
- *vp = JSVAL_VOID;
- return JS_TRUE;
- }
- #endif /* JS_GC_ZEAL */
- typedef struct JSCountHeapNode JSCountHeapNode;
- struct JSCountHeapNode {
- void *thing;
- int32 kind;
- JSCountHeapNode *next;
- };
- typedef struct JSCountHeapTracer {
- JSTracer base;
- JSDHashTable visited;
- JSBool ok;
- JSCountHeapNode *traceList;
- JSCountHeapNode *recycleList;
- } JSCountHeapTracer;
- static void
- CountHeapNotify(JSTracer *trc, void *thing, uint32 kind)
- {
- JSCountHeapTracer *countTracer;
- JSDHashEntryStub *entry;
- JSCountHeapNode *node;
- JS_ASSERT(trc->callback == CountHeapNotify);
- countTracer = (JSCountHeapTracer *)trc;
- if (!countTracer->ok)
- return;
- entry = (JSDHashEntryStub *)
- JS_DHashTableOperate(&countTracer->visited, thing, JS_DHASH_ADD);
- if (!entry) {
- JS_ReportOutOfMemory(trc->context);
- countTracer->ok = JS_FALSE;
- return;
- }
- if (entry->key)
- return;
- entry->key = thing;
- node = countTracer->recycleList;
- if (node) {
- countTracer->recycleList = node->next;
- } else {
- node = (JSCountHeapNode *) JS_malloc(trc->context, sizeof *node);
- if (!node) {
- countTracer->ok = JS_FALSE;
- return;
- }
- }
- node->thing = thing;
- node->kind = kind;
- node->next = countTracer->traceList;
- countTracer->traceList = node;
- }
- static JSBool
- CountHeap(JSContext *cx, uintN argc, jsval *vp)
- {
- void* startThing;
- int32 startTraceKind;
- jsval v;
- int32 traceKind, i;
- JSString *str;
- char *bytes;
- JSCountHeapTracer countTracer;
- JSCountHeapNode *node;
- size_t counter;
- static const struct {
- const char *name;
- int32 kind;
- } traceKindNames[] = {
- { "all", -1 },
- { "object", JSTRACE_OBJECT },
- { "double", JSTRACE_DOUBLE },
- { "string", JSTRACE_STRING },
- #if JS_HAS_XML_SUPPORT
- { "xml", JSTRACE_XML },
- #endif
- };
- startThing = NULL;
- startTraceKind = 0;
- if (argc > 0) {
- v = JS_ARGV(cx, vp)[0];
- if (JSVAL_IS_TRACEABLE(v)) {
- startThing = JSVAL_TO_TRACEABLE(v);
- startTraceKind = JSVAL_TRACE_KIND(v);
- } else if (v != JSVAL_NULL) {
- JS_ReportError(cx,
- "the first argument is not null or a heap-allocated "
- "thing");
- return JS_FALSE;
- }
- }
- traceKind = -1;
- if (argc > 1) {
- str = JS_ValueToString(cx, JS_ARGV(cx, vp)[1]);
- if (!str)
- return JS_FALSE;
- bytes = JS_GetStringBytes(str);
- if (!bytes)
- return JS_FALSE;
- for (i = 0; ;) {
- if (strcmp(bytes, traceKindNames[i].name) == 0) {
- traceKind = traceKindNames[i].kind;
- break;
- }
- if (++i == JS_ARRAY_LENGTH(traceKindNames)) {
- JS_ReportError(cx, "trace kind name '%s' is unknown", bytes);
- return JS_FALSE;
- }
- }
- }
- JS_TRACER_INIT(&countTracer.base, cx, CountHeapNotify);
- if (!JS_DHashTableInit(&countTracer.visited, JS_DHashGetStubOps(),
- NULL, sizeof(JSDHashEntryStub),
- JS_DHASH_DEFAULT_CAPACITY(100))) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
- countTracer.ok = JS_TRUE;
- countTracer.traceList = NULL;
- countTracer.recycleList = NULL;
- if (!startThing) {
- JS_TraceRuntime(&countTracer.base);
- } else {
- JS_SET_TRACING_NAME(&countTracer.base, "root");
- JS_CallTracer(&countTracer.base, startThing, startTraceKind);
- }
- counter = 0;
- while ((node = countTracer.traceList) != NULL) {
- if (traceKind == -1 || node->kind == traceKind)
- counter++;
- countTracer.traceList = node->next;
- node->next = countTracer.recycleList;
- countTracer.recycleList = node;
- JS_TraceChildren(&countTracer.base, node->thing, node->kind);
- }
- while ((node = countTracer.recycleList) != NULL) {
- countTracer.recycleList = node->next;
- JS_free(cx, node);
- }
- JS_DHashTableFinish(&countTracer.visited);
- return countTracer.ok && JS_NewNumberValue(cx, (jsdouble) counter, vp);
- }
- static JSScript *
- ValueToScript(JSContext *cx, jsval v)
- {
- JSScript *script;
- JSFunction *fun;
- if (!JSVAL_IS_PRIMITIVE(v) &&
- JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) {
- script = (JSScript *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(v));
- } else {
- fun = JS_ValueToFunction(cx, v);
- if (!fun)
- return NULL;
- script = FUN_SCRIPT(fun);
- }
- if (!script) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
- JSSMSG_SCRIPTS_ONLY);
- }
- return script;
- }
- static JSBool
- GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
- int32 *ip)
- {
- jsval v;
- uintN intarg;
- JSScript *script;
- *scriptp = cx->fp->down->script;
- *ip = 0;
- if (argc != 0) {
- v = argv[0];
- intarg = 0;
- if (!JSVAL_IS_PRIMITIVE(v) &&
- (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass ||
- JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass)) {
- script = ValueToScript(cx, v);
- if (!script)
- return JS_FALSE;
- *scriptp = script;
- intarg++;
- }
- if (argc > intarg) {
- if (!JS_ValueToInt32(cx, argv[intarg], ip))
- return JS_FALSE;
- }
- }
- return JS_TRUE;
- }
- static JSTrapStatus
- TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
- void *closure)
- {
- JSString *str;
- JSStackFrame *caller;
- str = (JSString *) closure;
- caller = JS_GetScriptedCaller(cx, NULL);
- if (!JS_EvaluateScript(cx, caller->scopeChain,
- JS_GetStringBytes(str), JS_GetStringLength(str),
- caller->script->filename, caller->script->lineno,
- rval)) {
- return JSTRAP_ERROR;
- }
- if (!JSVAL_IS_VOID(*rval))
- return JSTRAP_RETURN;
- return JSTRAP_CONTINUE;
- }
- static JSBool
- Trap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSString *str;
- JSScript *script;
- int32 i;
- if (argc == 0) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_TRAP_USAGE);
- return JS_FALSE;
- }
- argc--;
- str = JS_ValueToString(cx, argv[argc]);
- if (!str)
- return JS_FALSE;
- argv[argc] = STRING_TO_JSVAL(str);
- if (!GetTrapArgs(cx, argc, argv, &script, &i))
- return JS_FALSE;
- return JS_SetTrap(cx, script, script->code + i, TrapHandler, str);
- }
- static JSBool
- Untrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSScript *script;
- int32 i;
- if (!GetTrapArgs(cx, argc, argv, &script, &i))
- return JS_FALSE;
- JS_ClearTrap(cx, script, script->code + i, NULL, NULL);
- return JS_TRUE;
- }
- static JSBool
- LineToPC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSScript *script;
- int32 i;
- uintN lineno;
- jsbytecode *pc;
- if (argc == 0) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
- return JS_FALSE;
- }
- script = cx->fp->down->script;
- if (!GetTrapArgs(cx, argc, argv, &script, &i))
- return JS_FALSE;
- lineno = (i == 0) ? script->lineno : (uintN)i;
- pc = JS_LineNumberToPC(cx, script, lineno);
- if (!pc)
- return JS_FALSE;
- *rval = INT_TO_JSVAL(PTRDIFF(pc, script->code, jsbytecode));
- return JS_TRUE;
- }
- static JSBool
- PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSScript *script;
- int32 i;
- uintN lineno;
- if (!GetTrapArgs(cx, argc, argv, &script, &i))
- return JS_FALSE;
- lineno = JS_PCToLineNumber(cx, script, script->code + i);
- if (!lineno)
- return JS_FALSE;
- *rval = INT_TO_JSVAL(lineno);
- return JS_TRUE;
- }
- #ifdef DEBUG
- static void
- UpdateSwitchTableBounds(JSScript *script, uintN offset,
- uintN *start, uintN *end)
- {
- jsbytecode *pc;
- JSOp op;
- ptrdiff_t jmplen;
- jsint low, high, n;
- pc = script->code + offset;
- op = (JSOp) *pc;
- switch (op) {
- case JSOP_TABLESWITCHX:
- jmplen = JUMPX_OFFSET_LEN;
- goto jump_table;
- case JSOP_TABLESWITCH:
- jmplen = JUMP_OFFSET_LEN;
- jump_table:
- pc += jmplen;
- low = GET_JUMP_OFFSET(pc);
- pc += JUMP_OFFSET_LEN;
- high = GET_JUMP_OFFSET(pc);
- pc += JUMP_OFFSET_LEN;
- n = high - low + 1;
- break;
- case JSOP_LOOKUPSWITCHX:
- jmplen = JUMPX_OFFSET_LEN;
- goto lookup_table;
- case JSOP_LOOKUPSWITCH:
- jmplen = JUMP_OFFSET_LEN;
- lookup_table:
- pc += jmplen;
- n = GET_INDEX(pc);
- pc += INDEX_LEN;
- jmplen += JUMP_OFFSET_LEN;
- break;
- default:
- /* [condswitch] switch does not have any jump or lookup tables. */
- JS_ASSERT(op == JSOP_CONDSWITCH);
- return;
- }
- *start = (uintN)(pc - script->code);
- *end = *start + (uintN)(n * jmplen);
- }
- static void
- SrcNotes(JSContext *cx, JSScript *script)
- {
- uintN offset, delta, caseOff, switchTableStart, switchTableEnd;
- jssrcnote *notes, *sn;
- JSSrcNoteType type;
- const char *name;
- uint32 index;
- JSAtom *atom;
- JSString *str;
- fprintf(gOutFile, "\nSource notes:\n");
- offset = 0;
- notes = SCRIPT_NOTES(script);
- switchTableEnd = switchTableStart = 0;
- for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
- delta = SN_DELTA(sn);
- offset += delta;
- type = (JSSrcNoteType) SN_TYPE(sn);
- name = js_SrcNoteSpec[type].name;
- if (type == SRC_LABEL) {
- /* Check if the source note is for a switch case. */
- if (switchTableStart <= offset && offset < switchTableEnd) {
- name = "case";
- } else {
- JS_ASSERT(script->code[offset] == JSOP_NOP);
- }
- }
- fprintf(gOutFile, "%3u: %5u [%4u] %-8s",
- (uintN) PTRDIFF(sn, notes, jssrcnote), offset, delta, name);
- switch (type) {
- case SRC_SETLINE:
- fprintf(gOutFile, " lineno %u", (uintN) js_GetSrcNoteOffset(sn, 0));
- break;
- case SRC_FOR:
- fprintf(gOutFile, " cond %u update %u tail %u",
- (uintN) js_GetSrcNoteOffset(sn, 0),
- (uintN) js_GetSrcNoteOffset(sn, 1),
- (uintN) js_GetSrcNoteOffset(sn, 2));
- break;
- case SRC_IF_ELSE:
- fprintf(gOutFile, " else %u elseif %u",
- (uintN) js_GetSrcNoteOffset(sn, 0),
- (uintN) js_GetSrcNoteOffset(sn, 1));
- break;
- case SRC_COND:
- case SRC_WHILE:
- case SRC_PCBASE:
- case SRC_PCDELTA:
- case SRC_DECL:
- case SRC_BRACE:
- fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0));
- break;
- case SRC_LABEL:
- case SRC_LABELBRACE:
- case SRC_BREAK2LABEL:
- case SRC_CONT2LABEL:
- index = js_GetSrcNoteOffset(sn, 0);
- JS_GET_SCRIPT_ATOM(script, index, atom);
- JS_ASSERT(ATOM_IS_STRING(atom));
- str = ATOM_TO_STRING(atom);
- fprintf(gOutFile, " atom %u (", index);
- js_FileEscapedString(gOutFile, str, 0);
- putc(')', gOutFile);
- break;
- case SRC_FUNCDEF: {
- const char *bytes;
- JSObject *obj;
- JSFunction *fun;
- index = js_GetSrcNoteOffset(sn, 0);
- JS_GET_SCRIPT_OBJECT(script, index, obj);
- fun = (JSFunction *) JS_GetPrivate(cx, obj);
- str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
- bytes = str ? JS_GetStringBytes(str) : "N/A";
- fprintf(gOutFile, " function %u (%s)", index, bytes);
- break;
- }
- case SRC_SWITCH:
- fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0));
- caseOff = (uintN) js_GetSrcNoteOffset(sn, 1);
- if (caseOff)
- fprintf(gOutFile, " first case offset %u", caseOff);
- UpdateSwitchTableBounds(script, offset,
- &switchTableStart, &switchTableEnd);
- break;
- case SRC_CATCH:
- delta = (uintN) js_GetSrcNoteOffset(sn, 0);
- if (delta) {
- if (script->main[offset] == JSOP_LEAVEBLOCK)
- fprintf(gOutFile, " stack depth %u", delta);
- else
- fprintf(gOutFile, " guard delta %u", delta);
- }
- break;
- default:;
- }
- fputc('\n', gOutFile);
- }
- }
- static JSBool
- Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- uintN i;
- JSScript *script;
- for (i = 0; i < argc; i++) {
- script = ValueToScript(cx, argv[i]);
- if (!script)
- continue;
- SrcNotes(cx, script);
- }
- return JS_TRUE;
- }
- JS_STATIC_ASSERT(JSTRY_CATCH == 0);
- JS_STATIC_ASSERT(JSTRY_FINALLY == 1);
- JS_STATIC_ASSERT(JSTRY_ITER == 2);
- static const char* const TryNoteNames[] = { "catch", "finally", "iter" };
- static JSBool
- TryNotes(JSContext *cx, JSScript *script)
- {
- JSTryNote *tn, *tnlimit;
- if (script->trynotesOffset == 0)
- return JS_TRUE;
- tn = JS_SCRIPT_TRYNOTES(script)->vector;
- tnlimit = tn + JS_SCRIPT_TRYNOTES(script)->length;
- fprintf(gOutFile, "\nException table:\n"
- "kind stack start end\n");
- do {
- JS_ASSERT(tn->kind < JS_ARRAY_LENGTH(TryNoteNames));
- fprintf(gOutFile, " %-7s %6u %8u %8u\n",
- TryNoteNames[tn->kind], tn->stackDepth,
- tn->start, tn->start + tn->length);
- } while (++tn != tnlimit);
- return JS_TRUE;
- }
- static JSBool
- Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSBool lines;
- uintN i;
- JSScript *script;
- if (argc > 0 &&
- JSVAL_IS_STRING(argv[0]) &&
- !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), "-l")) {
- lines = JS_TRUE;
- argv++, argc--;
- } else {
- lines = JS_FALSE;
- }
- for (i = 0; i < argc; i++) {
- script = ValueToScript(cx, argv[i]);
- if (!script)
- return JS_FALSE;
- if (VALUE_IS_FUNCTION(cx, argv[i])) {
- JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
- if (fun && (fun->flags & JSFUN_FLAGS_MASK)) {
- uint16 flags = fun->flags;
- fputs("flags:", stdout);
- #define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
- SHOW_FLAG(LAMBDA);
- SHOW_FLAG(SETTER);
- SHOW_FLAG(GETTER);
- SHOW_FLAG(BOUND_METHOD);
- SHOW_FLAG(HEAVYWEIGHT);
- SHOW_FLAG(THISP_STRING);
- SHOW_FLAG(THISP_NUMBER);
- SHOW_FLAG(THISP_BOOLEAN);
- SHOW_FLAG(EXPR_CLOSURE);
- SHOW_FLAG(INTERPRETED);
- #undef SHOW_FLAG
- putchar('\n');
- }
- }
- if (!js_Disassemble(cx, script, lines, stdout))
- return JS_FALSE;
- SrcNotes(cx, script);
- TryNotes(cx, script);
- }
- return JS_TRUE;
- }
- static JSBool
- DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSString *str;
- const char *filename;
- JSScript *script;
- JSBool ok;
- uint32 oldopts;
-
- if (!argc)
- return JS_TRUE;
- str = JS_ValueToString(cx, argv[0]);
- if (!str)
- return JS_FALSE;
- argv[0] = STRING_TO_JSVAL(str);
- filename = JS_GetStringBytes(str);
- oldopts = JS_GetOptions(cx);
- JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
- script = JS_CompileFile(cx, obj, filename);
- JS_SetOptions(cx, oldopts);
- if (!script)
- return JS_FALSE;
- obj = JS_NewScriptObject(cx, script);
- if (!obj)
- return JS_FALSE;
-
- *rval = OBJECT_TO_JSVAL(obj); /* I like to root it, root it. */
- ok = Disassemble(cx, obj, 1, rval, rval); /* gross, but works! */
- *rval = JSVAL_VOID;
- return ok;
- }
- static JSBool
- DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- #define LINE_BUF_LEN 512
- uintN i, len, line1, line2, bupline;
- JSScript *script;
- FILE *file;
- char linebuf[LINE_BUF_LEN];
- jsbytecode *pc, *end;
- JSBool ok;
- static char sep[] = ";-------------------------";
- ok = JS_TRUE;
- for (i = 0; ok && i < argc; i++) {
- script = ValueToScript(cx, argv[i]);
- if (!script)
- return JS_FALSE;
- if (!script->filename) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
- JSSMSG_FILE_SCRIPTS_ONLY);
- return JS_FALSE;
- }
- file = fopen(script->filename, "r");
- if (!file) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
- JSSMSG_CANT_OPEN, script->filename,
- strerror(errno));
- return JS_FALSE;
- }
- pc = script->code;
- end = pc + script->length;
- /* burn the leading lines */
- line2 = JS_PCToLineNumber(cx, script, pc);
- for (line1 = 0; line1 < line2 - 1; line1++)
- fgets(linebuf, LINE_BUF_LEN, file);
- bupline = 0;
- while (pc < end) {
- line2 = JS_PCToLineNumber(cx, script, pc);
- if (line2 < line1) {
- if (bupline != line2) {
- bupline = line2;
- fprintf(gOutFile, "%s %3u: BACKUP\n", sep, line2);
- }
- } else {
- if (bupline && line1 == line2)
- fprintf(gOutFile, "%s %3u: RESTORE\n", sep, line2);
- bupline = 0;
- while (line1 < line2) {
- if (!fgets(linebuf, LINE_BUF_LEN, file)) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
- JSSMSG_UNEXPECTED_EOF,
- script->filename);
- ok = JS_FALSE;
- goto bail;
- }
- line1++;
- fprintf(gOutFile, "%s %3u: %s", sep, line1, linebuf);
- }
- }
- len = js_Disassemble1(cx, script, pc,
- PTRDIFF(pc, script->code, jsbytecode),
- JS_TRUE, stdout);
- if (!len) {
- ok = JS_FALSE;
- goto bail;
- }
- pc += len;
- }
- bail:
- fclose(file);
- }
- return ok;
- #undef LINE_BUF_LEN
- }
- static JSBool
- Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSBool bval;
- JSString *str;
- #if JS_THREADED_INTERP
- JS_ReportError(cx, "tracing not supported in JS_THREADED_INTERP builds");
- return JS_FALSE;
- #else
- if (argc == 0) {
- *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0);
- return JS_TRUE;
- }
- switch (JS_TypeOfValue(cx, argv[0])) {
- case JSTYPE_NUMBER:
- bval = JSVAL_IS_INT(argv[0])
- ? JSVAL_TO_INT(argv[0])
- : (jsint) *JSVAL_TO_DOUBLE(argv[0]);
- break;
- case JSTYPE_BOOLEAN:
- bval = JSVAL_TO_BOOLEAN(argv[0]);
- break;
- default:
- str = JS_ValueToString(cx, argv[0]);
- if (!str)
- return JS_FALSE;
- JS_ReportError(cx, "tracing: illegal argument %s",
- JS_GetStringBytes(str));
- return JS_FALSE;
- }
- cx->tracefp = bval ? stderr : NULL;
- return JS_TRUE;
- #endif
- }
- static void
- DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
- {
- uintN i;
- JSScope *scope;
- JSScopeProperty *sprop;
- jsval v;
- JSString *str;
- i = 0;
- scope = OBJ_SCOPE(obj);
- for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
- if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
- continue;
- fprintf(fp, "%3u %p ", i, (void *)sprop);
- v = ID_TO_VALUE(sprop->id);
- if (JSID_IS_INT(sprop->id)) {
- fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v));
- } else {
- if (JSID_IS_ATOM(sprop->id)) {
- str = JSVAL_TO_STRING(v);
- } else {
- JS_ASSERT(JSID_IS_OBJECT(sprop->id));
- str = js_ValueToString(cx, v);
- fputs("object ", fp);
- }
- if (!str)
- fputs("<error>", fp);
- else
- js_FileEscapedString(fp, str, '"');
- }
- #define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
- DUMP_ATTR(ENUMERATE);
- DUMP_ATTR(READONLY);
- DUMP_ATTR(PERMANENT);
- DUMP_ATTR(GETTER);
- DUMP_ATTR(SETTER);
- #undef DUMP_ATTR
- fprintf(fp, " slot %lu flags %x shortid %d\n",
- (unsigned long)sprop->slot, sprop->flags, sprop->shortid);
- }
- }
- static JSBool
- DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- uintN i;
- JSString *str;
- const char *bytes;
- jsid id;
- JSObject *obj2;
- JSProperty *prop;
- jsval value;
- for (i = 0; i < argc; i++) {
- str = JS_ValueToString(cx, argv[i]);
- if (!str)
- return JS_FALSE;
- argv[i] = STRING_TO_JSVAL(str);
- bytes = JS_GetStringBytes(str);
- if (strcmp(bytes, "arena") == 0) {
- #ifdef JS_ARENAMETER
- JS_DumpArenaStats(stdout);
- #endif
- } else if (strcmp(bytes, "atom") == 0) {
- js_DumpAtoms(cx, gOutFile);
- } else if (strcmp(bytes, "global") == 0) {
- DumpScope(cx, cx->globalObject, stdout);
- } else {
- if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id))
- return JS_FALSE;
- if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
- return JS_FALSE;
- if (prop) {
- OBJ_DROP_PROPERTY(cx, obj2, prop);
- if (!OBJ_GET_PROPERTY(cx, obj, id, &value))
- return JS_FALSE;
- }
- if (!prop || !JSVAL_IS_OBJECT(value)) {
- fprintf(gErrFile, "js: invalid stats argument %s\n",
- bytes);
- continue;
- }
- obj = JSVAL_TO_OBJECT(value);
- if (obj)
- DumpScope(cx, obj, stdout);
- }
- }
- return JS_TRUE;
- }
- static JSBool
- DumpHeap(JSContext *cx, uintN argc, jsval *vp)
- {
- char *fileName;
- jsval v;
- void* startThing;
- uint32 startTraceKind;
- const char *badTraceArg;
- void *thingToFind;
- size_t maxDepth;
- void *thingToIgnore;
- FILE *dumpFile;
- JSBool ok;
- fileName = NULL;
- if (argc > 0) {
- v = JS_ARGV(cx, vp)[0];
- if (v != JSVAL_NULL) {
- JSString *str;
- str = JS_ValueToString(cx, v);
- if (!str)
- return JS_FALSE;
- JS_ARGV(cx, vp)[0] = STRING_TO_JSVAL(str);
- fileName = JS_GetStringBytes(str);
- }
- }
- startThing = NULL;
- startTraceKind = 0;
- if (argc > 1) {
- v = JS_ARGV(cx, vp)[1];
- if (JSVAL_IS_TRACEABLE(v)) {
- startThing = JSVAL_TO_TRACEABLE(v);
- startTraceKind = JSVAL_TRACE_KIND(v);
- } else if (v != JSVAL_NULL) {
- badTraceArg = "start";
- goto not_traceable_arg;
- }
- }
- thingToFind = NULL;
- if (argc > 2) {
- v = JS_ARGV(cx, vp)[2];
- if (JSVAL_IS_TRACEABLE(v)) {
- thingToFind = JSVAL_TO_TRACEABLE(v);
- } else if (v != JSVAL_NULL) {
- badTraceArg = "toFind";
- goto not_traceable_arg;
- }
- }
- maxDepth = (size_t)-1;
- if (argc > 3) {
- v = JS_ARGV(cx, vp)[3];
- if (v != JSVAL_NULL) {
- uint32 depth;
- if (!JS_ValueToECMAUint32(cx, v, &depth))
- return JS_FALSE;
- maxDepth = depth;
- }
- }
- thingToIgnore = NULL;
- if (argc > 4) {
- v = JS_ARGV(cx, vp)[4];
- if (JSVAL_IS_TRACEABLE(v)) {
- thingToIgnore = JSVAL_TO_TRACEABLE(v);
- } else if (v != JSVAL_NULL) {
- badTraceArg = "toIgnore";
- goto not_traceable_arg;
- }
- }
- if (!fileName) {
- dumpFile = stdout;
- } else {
- dumpFile = fopen(fileName, "w");
- if (!dumpFile) {
- JS_ReportError(cx, "can't open %s: %s", fileName, strerror(errno));
- return JS_FALSE;
- }
- }
- ok = JS_DumpHeap(cx, dumpFile, startThing, startTraceKind, thingToFind,
- maxDepth, thingToIgnore);
- if (dumpFile != stdout)
- fclose(dumpFile);
- return ok;
- not_traceable_arg:
- JS_ReportError(cx, "argument '%s' is not null or a heap-allocated thing",
- badTraceArg);
- return JS_FALSE;
- }
- #endif /* DEBUG */
- #ifdef TEST_CVTARGS
- #include <ctype.h>
- static const char *
- EscapeWideString(jschar *w)
- {
- static char enuf[80];
- static char hex[] = "0123456789abcdef";
- jschar u;
- unsigned char b, c;
- int i, j;
- if (!w)
- return "";
- for (i = j = 0; i < sizeof enuf - 1; i++, j++) {
- u = w[j];
- if (u == 0)
- break;
- b = (unsigned char)(u >> 8);
- c = (unsigned char)(u);
- if (b) {
- if (i >= sizeof enuf - 6)
- break;
- enuf[i++] = '\\';
- enuf[i++] = 'u';
- enuf[i++] = hex[b >> 4];
- enuf[i++] = hex[b & 15];
- enuf[i++] = hex[c >> 4];
- enuf[i] = hex[c & 15];
- } else if (!isprint(c)) {
- if (i >= sizeof enuf - 4)
- break;
- enuf[i++] = '\\';
- enuf[i++] = 'x';
- enuf[i++] = hex[c >> 4];
- enuf[i] = hex[c & 15];
- } else {
- enuf[i] = (char)c;
- }
- }
- enuf[i] = 0;
- return enuf;
- }
- #include <stdarg.h>
- static JSBool
- ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp,
- va_list *app)
- {
- jsval *vp;
- va_list ap;
- jsdouble re, im;
- printf("entering ZZ_formatter");
- vp = *vpp;
- ap = *app;
- if (fromJS) {
- if (!JS_ValueToNumber(cx, vp[0], &re))
- return JS_FALSE;
- if (!JS_ValueToNumber(cx, vp[1], &im))
- return JS_FALSE;
- *va_arg(ap, jsdouble *) = re;
- *va_arg(ap, jsdouble *) = im;
- } else {
- re = va_arg(ap, jsdouble);
- im = va_arg(ap, jsdouble);
- if (!JS_NewNumberValue(cx, re, &vp[0]))
- return JS_FALSE;
- if (!JS_NewNumberValue(cx, im, &vp[1]))
- return JS_FALSE;
- }
- *vpp = vp + 2;
- *app = ap;
- printf("leaving ZZ_formatter");
- return JS_TRUE;
- }
- static JSBool
- ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSBool b = JS_FALSE;
- jschar c = 0;
- int32 i = 0, j = 0;
- uint32 u = 0;
- jsdouble d = 0, I = 0, re = 0, im = 0;
- char *s = NULL;
- JSString *str = NULL;
- jschar *w = NULL;
- JSObject *obj2 = NULL;
- JSFunction *fun = NULL;
- jsval v = JSVAL_VOID;
- JSBool ok;
- if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter))
- return JS_FALSE;;
- ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*",
- &b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2,
- &fun, &v, &re, &im);
- JS_RemoveArgumentFormatter(cx, "ZZ");
- if (!ok)
- return JS_FALSE;
- fprintf(gOutFile,
- "b %u, c %x (%c), i %ld, u %lu, j %ld\n",
- b, c, (char)c, i, u, j);
- fprintf(gOutFile,
- "d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n"
- "v %s, re %g, im %g\n",
- d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w),
- JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj2))),
- fun ? JS_GetStringBytes(JS_DecompileFunction(cx, fun, 4)) : "",
- JS_GetStringBytes(JS_ValueToString(cx, v)), re, im);
- return JS_TRUE;
- }
- #endif
- static JSBool
- BuildDate(JSContext *cx, uintN argc, jsval *vp)
- {
- char version[20] = "\n";
- #if JS_VERSION < 150
- sprintf(version, " for version %d\n", JS_VERSION);
- #endif
- fprintf(gOutFile, "built on %s at %s%s", __DATE__, __TIME__, version);
- *vp = JSVAL_VOID;
- return JS_TRUE;
- }
- static JSBool
- Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- if (argc != 0 && !JS_ValueToObject(cx, argv[0], &obj))
- return JS_FALSE;
- JS_ClearScope(cx, obj);
- return JS_TRUE;
- }
- static JSBool
- Intern(JSContext *cx, uintN argc, jsval *vp)
- {
- JSString *str;
- str = JS_ValueToString(cx, argc == 0 ? JSVAL_VOID : vp[2]);
- if (!str)
- return JS_FALSE;
- if (!JS_InternUCStringN(cx, JS_GetStringChars(str),
- JS_GetStringLength(str))) {
- return JS_FALSE;
- }
- *vp = JSVAL_VOID;
- return JS_TRUE;
- }
- static JSBool
- Clone(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSFunction *fun;
- JSObject *funobj, *parent, *clone;
- fun = JS_ValueToFunction(cx, argv[0]);
- if (!fun)
- return JS_FALSE;
- funobj = JS_GetFunctionObject(fun);
- if (argc > 1) {
- if (!JS_ValueToObject(cx, argv[1], &parent))
- return JS_FALSE;
- } else {
- parent = JS_GetParent(cx, funobj);
- }
- clone = JS_CloneFunctionObject(cx, funobj, parent);
- if (!clone)
- return JS_FALSE;
- *rval = OBJECT_TO_JSVAL(clone);
- return JS_TRUE;
- }
- static JSBool
- Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JSObject *target;
- JSBool deep = JS_FALSE;
- if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
- return JS_FALSE;
- if (!target)
- return JS_TRUE;
- return JS_SealObject(cx, target, deep);
- }
- static JSBool
- GetPDA(JSContext *cx, uintN argc, jsval *vp)
- {
- JSObject *vobj, *aobj, *pdobj;
- JSBool ok;
- JSPropertyDescArray pda;
- JSPropertyDesc *pd;
- uint32 i;
- jsval v;
- if (!JS_ValueToObject(cx, argc == 0 ? JSVAL_VOID : vp[2], &vobj))
- return JS_FALSE;
- if (!vobj)
- return JS_TRUE;
- aobj = JS_NewArrayObject(cx, 0, NULL);
- if (!aobj)
- return JS_FALSE;
- *vp = OBJECT_TO_JSVAL(aobj);
- ok = JS_GetPropertyDescArray(cx, vobj, &pda);
- if (!ok)
- return JS_FALSE;
- pd = pda.array;
- for (i = 0; i < pda.length; i++) {
- pdobj = JS_NewObject(cx, NULL, NULL, NULL);
- if (!pdobj) {
- ok = JS_FALSE;
- break;
- }
- /* Protect pdobj from GC by setting it as an element of aobj now */
- v = OBJECT_TO_JSVAL(pdobj);
- ok = JS_SetElement(cx, aobj, i, &v);
- if (!ok)
- break;
- ok = JS_SetProperty(cx, pdobj, "id", &pd->id) &&
- JS_SetProperty(cx, pdobj, "value", &pd->value) &&
- (v = INT_TO_JSVAL(pd->flags),
- JS_SetProperty(cx, pdobj, "flags", &v)) &&
- (v = INT_TO_JSVAL(pd->slot),
- JS_SetProperty(cx, pdobj, "slot", &v)) &&
- JS_SetProperty(cx, pdobj, "alias", &pd->alias);
- if (!ok)
- break;
- }
- JS_PutPropertyDescArray(cx, &pda);
- return ok;
- }
- static JSBool
- GetSLX(JSContext *cx, uintN argc, jsval *vp)
- {
- JSScript *script;
- script = ValueToScript(cx, argc == 0 ? JSVAL_VOID : vp[2]);
- if (!script)
- return JS_FALSE;
- *vp = INT_TO_JSVAL(js_GetScriptLineExtent(script));
- return JS_TRUE;
- }
- static JSBool
- ToInt32(JSContext *cx, uintN argc, jsval *vp)
- {
- int32 i;
- if (!JS_ValueToInt32(cx, argc == 0 ? JSVAL_VOID : vp[2], &i))
- return JS_FALSE;
- return JS_NewNumberValue(cx, i, vp);
- }
- static JSBool
- StringsAreUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
- jsval *rval)
- {
- *rval = JS_CStringsAreUTF8() ? JSVAL_TRUE : JSVAL_FALSE;
- return JS_TRUE;
- }
- static JSBool
- StackQuota(JSContext *cx, uintN argc, jsval *vp)
- {
- uint32 n;
- if (argc == 0)
- return JS_NewNumberValue(cx, (double) gScriptStackQuota, vp);
- if (!JS_ValueToECMAUint32(cx, JS_ARGV(cx, vp)[0], &n))
- return JS_FALSE;
- gScriptStackQuota = n;
- JS_SetScriptStackQuota(cx, gScriptStackQuota);
- JS_SET_RVAL(cx, vp, JSVAL_VOID);
- return JS_TRUE;
- }
- static const char* badUTF8 = "...\xC0...";
- static const char* bigUTF8 = "...\xFB\xBF\xBF\xBF\xBF...";
- static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 };
- static JSBool
- TestUTF8(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- int32 mode = 1;
- jschar chars[20];
- size_t charsLength = 5;
- char bytes[20];
- size_t bytesLength = 20;
- if (argc && !JS_ValueToInt32(cx, *argv, &mode))
- return JS_FALSE;
- /* The following throw errors if compiled with UTF-8. */
- switch (mode) {
- /* mode 1: malformed UTF-8 string. */
- case 1:
- JS_NewStringCopyZ(cx, badUTF8);
- break;
- /* mode 2: big UTF-8 character. */
- case 2:
- JS_NewStringCopyZ(cx, bigUTF8);
- break;
- /* mode 3: bad surrogate character. */
- case 3:
- JS_EncodeCharacters(cx, badSurrogate, 6, bytes, &bytesLength);
- break;
- /* mode 4: use a too small buffer. */
- case 4:
- JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength);
- break;
- default:
- JS_ReportError(cx, "invalid mode parameter");
- return JS_FALSE;
- }
- return !JS_IsExceptionPending (cx);
- }
- static JSBool
- ThrowError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
- {
- JS_ReportError(cx, "This is an error");
- return JS_FALSE;
- }
- #define LAZY_STANDARD_CLASSES
- /* A class for easily testing the inner/outer object callbacks. */
- typedef struct ComplexObject {
- JSBool isInner;
- JSBool frozen;
- JSObject *inner;
- JSObject *outer;
- } ComplexObject;
- static JSObject *
- split_create_outer(JSContext *cx);
- static JSObject *
- split_create_inner(JSContext *cx, JSObject *outer);
- static ComplexObject *
- split_get_private(JSContext *cx, JSObject *obj);
- static JSBool
- split_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- ComplexObject *cpx;
- jsid asId;
- cpx = split_get_private(cx, obj);
- if (!cpx)
- return JS_TRUE;
- if (!cpx->isInner && cpx->inner) {
- /* Make sure to define this property on the inner object. */
- if (!JS_ValueToId(cx, *vp, &asId))
- return JS_FALSE;
- return OBJ_DEFINE_PROPERTY(cx, cpx->inner, asId, *vp, NULL, NULL,
- JSPROP_ENUMERATE, NULL);
- }
- return JS_TRUE;
- }
- static JSBool
- split_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- ComplexObject *cpx;
- cpx = split_get_private(cx, obj);
- if (!cpx)
- return JS_TRUE;
- if (!cpx->isInner && cpx->inner) {
- if (JSVAL_IS_STRING(id)) {
- JSString *str;
- str = JSVAL_TO_STRING(id);
- return JS_GetUCProperty(cx, cpx->inner, JS_GetStringChars(str),
- JS_GetStringLength(str), vp);
- }
- if (JSVAL_IS_INT(id))
- return JS_GetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp);
- return JS_TRUE;
- }
- return JS_TRUE;
- }
- static JSBool
- split_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- ComplexObject *cpx;
- cpx = split_get_private(cx, obj);
- if (!cpx)
- return JS_TRUE;
- if (!cpx->isInner && cpx->inner) {
- if (JSVAL_IS_STRING(id)) {
- JSString *str;
- str = JSVAL_TO_STRING(id);
- return JS_SetUCProperty(cx, cpx->inner, JS_GetStringChars(str),
- JS_GetStringLength(str), vp);
- }
- if (JSVAL_IS_INT(id))
- return JS_SetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp);
- return JS_TRUE;
- }
- return JS_TRUE;
- }
- static JSBool
- split_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- ComplexObject *cpx;
- jsid asId;
- cpx = split_get_private(cx, obj);
- if (!cpx)
- return JS_TRUE;
- if (!cpx->isInner && cpx->inner) {
- /* Make sure to define this property on the inner object. */
- if (!JS_ValueToId(cx, *vp, &asId))
- return JS_FALSE;
- return OBJ_DELETE_PROPERTY(cx, cpx->inner, asId, vp);
- }
- return JS_TRUE;
- }
- static JSBool
- split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
- jsval *statep, jsid *idp)
- {
- ComplexObject *cpx;
- JSObject *iterator;
- switch (enum_op) {
- case JSENUMERATE_INIT:
- cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
- if (!cpx->isInner && cpx->inner)
- obj = cpx->inner;
- iterator = JS_NewPropertyIterator(cx, obj);
- if (!iterator)
- return JS_FALSE;
- *statep = OBJECT_TO_JSVAL(iterator);
- if (idp)
- *idp = JSVAL_ZERO;
- break;
- case JSENUMERATE_NEXT:
- iterator = (JSObject*)JSVAL_TO_OBJECT(*statep);
- if (!JS_NextProperty(cx, iterator, idp))
- return JS_FALSE;
- if (!JSVAL_IS_VOID(*idp))
- break;
- /* Fall through. */
- case JSENUMERATE_DESTROY:
- /* Let GC at our iterator object. */
- *statep = JSVAL_NULL;
- break;
- }
- return JS_TRUE;
- }
- static JSBool
- split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
- JSObject **objp)
- {
- ComplexObject *cpx;
- cpx = split_get_private(cx, obj);
- if (!cpx)
- return JS_TRUE;
- if (!cpx->isInner && cpx->inner) {
- jsid asId;
- JSProperty *prop;
- if (!JS_ValueToId(cx, id, &asId))
- return JS_FALSE;
- if (!OBJ_LOOKUP_PROPERTY(cx, cpx->inner, asId, objp, &prop))
- return JS_FALSE;
- if (prop)
- OBJ_DROP_PROPERTY(cx, cpx->inner, prop);
- return JS_TRUE;
- }
- #ifdef LAZY_STANDARD_CLASSES
- if (!(flags & JSRESOLVE_ASSIGNING)) {
- JSBool resolved;
- if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
- return JS_FALSE;
- if (resolved) {
- *objp = obj;
- return JS_TRUE;
- }
- }
- #endif
- /* XXX For additional realism, let's resolve some random property here. */
- return JS_TRUE;
- }
- static void
- split_finalize(JSContext *cx, JSObject *obj)
- {
- JS_free(cx, JS_GetPrivate(cx, obj));
- }
- static uint32
- split_mark(JSContext *cx, JSObject *obj, void *arg)
- {
- ComplexObject *cpx;
- cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
- if (!cpx->isInner && cpx->inner) {
- /* Mark the inner object. */
- JS_MarkGCThing(cx, cpx->inner, "ComplexObject.inner", arg);
- }
- return 0;
- }
- static JSObject *
- split_outerObject(JSContext *cx, JSObject *obj)
- {
- ComplexObject *cpx;
- cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
- return cpx->isInner ? cpx->outer : obj;
- }
- static JSObject *
- split_innerObject(JSContext *cx, JSObject *obj)
- {
- ComplexObject *cpx;
- cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
- if (cpx->frozen) {
- JS_ASSERT(!cpx->isInner);
- return obj;
- }
- return !cpx->isInner ? cpx->inner : obj;
- }
- static JSExtendedClass split_global_class = {
- {"split_global",
- JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE |
- JSCLASS_GLOBAL_FLAGS | JSCLASS_IS_EXTENDED,
- split_addProperty, split_delProperty,
- split_getProperty, split_setProperty,
- (JSEnumerateOp)split_enumerate,
- (JSResolveOp)split_resolve,
- JS_ConvertStub, split_finalize,
- NULL, NULL, NULL, NULL, NULL, NULL,
- split_mark, NULL},
- NULL, split_outerObject, split_innerObject,
- NULL, NULL, NULL, NULL, NULL
- };
- JSObject *
- split_create_outer(JSContext *cx)
- {
- ComplexObject *cpx;
- JSObject *obj;
- cpx = (ComplexObject *) JS_malloc(cx, sizeof *obj);
- if (!cpx)
- return NULL;
- cpx->isInner = JS_FALSE;
- cpx->frozen = JS_TRUE;
- cpx->inner = NULL;
- cpx->outer = NULL;
- obj = JS_NewObject(cx, &split_global_class.base, NULL, NULL);
- if (!obj || !JS_SetParent(cx, obj, NULL)) {
- JS_free(cx, cpx);
- return NULL;
- }
- if (!JS_SetPrivate(cx, obj, cpx)) {
- JS_free(cx, cpx);
- return NULL;
- }
- return obj;
- }
- static JSObject *
- split_create_inner(JSContext *cx, JSObject *outer)
- {
- ComplexObject *cpx, *outercpx;
- JSObject *obj;
- JS_ASSERT(JS_GET_CLASS(cx, outer) == &split_global_class.base);
- cpx = (ComplexObject *) JS_malloc(cx, sizeof *cpx);
- if (!cpx)
- return NULL;
- cpx->isInner = JS_TRUE;
- cpx->frozen = JS_FALSE;
- cpx->inner = NULL;
- cpx->outer = outer;
- obj = JS_NewObject(cx, &split_global_class.base, NULL, NULL);
- if (!obj || !JS_SetParent(cx, obj, NULL) || !JS_SetPrivate(cx, obj, cpx)) {
- JS_free(cx, cpx);
- return NULL;
- }
- outercpx = (ComplexObj