PageRenderTime 60ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/js.cpp

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